Compare commits

...

28 Commits

Author SHA1 Message Date
Rohan Sircar 01f2676ca3 minor improvements 9 months ago
Rohan Sircar c25f2e0810 make logback stfu + minor edits 9 months ago
Rohan Sircar ddefc489e7 Add app prefix to env variables 9 months ago
Rohan Sircar 4262e045f5 fix mistake in env variable 9 months ago
Rohan Sircar 17f51bf16a
Update ci.yaml 9 months ago
Rohan Sircar 66e4d09b1d
Update ci.yaml 9 months ago
Rohan Sircar b350b4130e revert formatting change 9 months ago
Rohan Sircar bfee57e339 update ci file 9 months ago
Rohan Sircar aaf2ddcd25 Add env variables for app db user and pass 9 months ago
Rohan Sircar 6155857873 Update buildinfo fields 9 months ago
Rohan Sircar 621a3d8b8f move some files around 9 months ago
Rohan Sircar 5543ffe33d Add readme 9 months ago
Rohan Sircar 584e61fdb0 Add linters and update ci file 9 months ago
Rohan Sircar 04a8e8fd2e Add lint stage 9 months ago
Rohan Sircar ddb2e45754 temp commit 9 months ago
Rohan Sircar fa0e598602 Remove commented code 9 months ago
Rohan Sircar 2ff30c8615 Add sbt dynver 9 months ago
Rohan Sircar 5d12bdd3ce
Update ci.yaml 9 months ago
Rohan Sircar f70b77fadb Update CI file 9 months ago
Rohan Sircar e4019c9a63 Change postgres image version in integration test 9 months ago
Rohan Sircar 2527e3198e Update CI 9 months ago
Rohan Sircar 887808508c
Update ci.yaml 9 months ago
Rohan Sircar 3dc945cc70
Update build.yaml (#1) 9 months ago
Rohan Sircar 7dc86fda8e
Update build.yaml 9 months ago
Rohan Sircar 4c71b0f9e8
Update build.yaml 9 months ago
Rohan Sircar c7860c6611 temp commit 9 months ago
Rohan Sircar b6070c9fe6 fix captain-def imagename field 9 months ago
Rohan Sircar 479b571201 temp 9 months ago
  1. 178
      .github/workflows/ci.yaml
  2. 3
      .gitignore
  3. 1
      .scalafix.conf
  4. 1
      README.MD
  5. 184
      build.sbt
  6. BIN
      lib/monix-bio_2.13.jar
  7. 6
      modules/flyway/src/main/resources/db/migration/default/V1__create_users_table.sql
  8. 36
      modules/flyway/src/main/resources/db/migration/default/V1__library_schema.sql
  9. 6
      modules/flyway/src/main/resources/db/migration/default/V2__add_user.sql
  10. 69
      modules/flyway/src/main/resources/db/migration/default/V2__sample_data.sql
  11. 6
      modules/flyway/src/main/resources/db/migration/default/V3__create_cars_table.sql
  12. 6
      modules/flyway/src/main/resources/db/migration/default/V4__add_car.sql
  13. 12
      modules/flyway/src/main/resources/db/migration/default/V5__authors_books_table.sql
  14. 14
      modules/flyway/src/main/resources/db/migration/default/V6__insert_books_and_authors.sql
  15. 26
      modules/test-common/src/main/scala/wow/doge/MonixBioSuite.scala
  16. 13
      project/plugins.sbt
  17. 5
      scripts/.env
  18. 46
      scripts/app.Dockerfile
  19. 7
      scripts/app.sh
  20. 24
      scripts/build.sh
  21. 7
      scripts/curl
  22. 4
      scripts/db.Dockerfile
  23. 6
      scripts/db.sh
  24. 41
      scripts/docker-compose.yml
  25. 11
      scripts/native
  26. 0
      scripts/native-image-readme.md
  27. 4
      scripts/test.Dockerfile
  28. 182
      scripts/wait-for-it.sh
  29. 10
      src/it/resources/logback-test.xml
  30. 112
      src/it/scala/wow/doge/http4sdemo/DatabaseIntegrationTestBase.scala
  31. 121
      src/it/scala/wow/doge/http4sdemo/LibraryServiceSpec.scala
  32. 22
      src/main/resources/META-INF/native-image/wow/doge/http4sdemo/jni-config.json
  33. 309
      src/main/resources/META-INF/native-image/wow/doge/http4sdemo/reflect-config.json
  34. 19
      src/main/resources/META-INF/native-image/wow/doge/http4sdemo/resource-config.json
  35. 2
      src/main/resources/META-INF/native-image/wow/doge/http4sdemo/serialization-config.json
  36. 56
      src/main/resources/application.conf
  37. 144
      src/main/scala/wow/doge/http4sdemo/Http4sdemoRoutes.scala
  38. 50
      src/main/scala/wow/doge/http4sdemo/Http4sdemoServer.scala
  39. 47
      src/main/scala/wow/doge/http4sdemo/Jokes.scala
  40. 31
      src/main/scala/wow/doge/http4sdemo/Main.scala
  41. 1
      src/main/scala/wow/doge/http4sdemo/Migrate.scala
  42. 43
      src/main/scala/wow/doge/http4sdemo/Server.scala
  43. 4
      src/main/scala/wow/doge/http4sdemo/SlickResource.scala
  44. 79
      src/main/scala/wow/doge/http4sdemo/dto/Library.scala
  45. 23
      src/main/scala/wow/doge/http4sdemo/implicits/package.scala
  46. 114
      src/main/scala/wow/doge/http4sdemo/routes/LibraryRoutes.scala
  47. 245
      src/main/scala/wow/doge/http4sdemo/services/LibraryService.scala
  48. 10
      src/test/resources/logback-test.xml
  49. 25
      src/test/scala/wow/doge/http4sdemo/HelloWorldSpec.scala
  50. 156
      src/test/scala/wow/doge/http4sdemo/LibraryControllerSpec.scala

178
.github/workflows/ci.yaml

@ -0,0 +1,178 @@
---
name: Continuous Integration
on:
pull_request:
branches: ["*", series/*]
paths-ignore:
- ".dockerignore"
- ".github/workflow/ci.yml"
- "Changelog.md"
- "Dockerfile"
- "doc/**"
- "docker/**"
- "LICENSE"
- "README.md"
# - "tests/e2e/**"
push:
branches: ["*", series/*]
tags: [v*]
paths-ignore:
- ".dockerignore"
- ".github/workflow/ci.yml"
- "Changelog.md"
- "Dockerfile"
- "doc/**"
- "docker/**"
- "LICENSE"
- "README.md"
# - "tests/e2e/**"
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
env:
HTTP4S_DEMO_CODEGEN_DB_HOST: localhost
HTTP4S_DEMO_CODEGEN_DB_PORT: 5432
HTTP4S_DEMO_CODEGEN_DB_USER: codegenuser
HTTP4S_DEMO_CODEGEN_DB_PASSWORD: postgres
HTTP4S_DEMO_CODEGEN_DB_NAME: codegendb
services:
postgres:
image: postgres:12-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: codegenuser
POSTGRES_DB: codegendb
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Coursier cache
uses: coursier/cache-action@v6
- name: Setup
uses: olafurpg/setup-scala@v10
with:
java-version: adopt@1.11
- name: Migrate
run: csbt flyway/flywayMigrate
- name: Lint
run: csbt lint-check
- name: Compile
run: |
csbt "compile; test:compile"
- name: Run Unit Tests
run: |
csbt test
- name: Run Integration Tests
run: |
csbt it:test
publish:
name: Publish Release Docker Image
needs: [build]
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
runs-on: ubuntu-latest
env:
HTTP4S_DEMO_CODEGEN_DB_HOST: localhost
HTTP4S_DEMO_CODEGEN_DB_PORT: 5432
HTTP4S_DEMO_CODEGEN_DB_USER: codegenuser
HTTP4S_DEMO_CODEGEN_DB_PASSWORD: postgres
HTTP4S_DEMO_CODEGEN_DB_NAME: codegendb
HTTP4S_DEMO_DOCKER_JAVA_IMAGE: azul/zulu-openjdk-alpine:11-jre-headless
services:
postgres:
image: postgres:12-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: codegenuser
POSTGRES_DB: codegendb
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Coursier cache
uses: coursier/cache-action@v6
- name: Setup
uses: olafurpg/setup-scala@v10
with:
java-version: adopt@1.11
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: rohansircar
password: ${{ secrets.DOCKER_LOGIN_PASSWORD }}
- name: Migrate
run: csbt flyway/flywayMigrate
- name: Publish Tag
if: startsWith(github.ref, 'refs/tags/v')
run: |
csbt docker:publish
- name: Publish Latest
if: github.ref == 'refs/heads/main'
env:
DOCKER_PUBLISH_TAG: latest
run: |
csbt docker:publish
publish-devel:
name: Publish Devel Docker Image
needs: [build]
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/devel'
runs-on: ubuntu-latest
env:
HTTP4S_DEMO_CODEGEN_DB_HOST: localhost
HTTP4S_DEMO_CODEGEN_DB_PORT: 5432
HTTP4S_DEMO_CODEGEN_DB_USER: codegenuser
HTTP4S_DEMO_CODEGEN_DB_PASSWORD: postgres
HTTP4S_DEMO_CODEGEN_DB_NAME: codegendb
HTTP4S_DEMO_DOCKER_JAVA_IMAGE: azul/zulu-openjdk-alpine:11-jre-headless
HTTP4S_DEMO_DOCKER_PUBLISH_TAG: devel
services:
postgres:
image: postgres:12-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: codegenuser
POSTGRES_DB: codegendb
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Coursier cache
uses: coursier/cache-action@v6
- name: Setup
uses: olafurpg/setup-scala@v10
with:
java-version: adopt@1.11
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: rohansircar
password: ${{ secrets.DOCKER_LOGIN_PASSWORD }}
- name: Migrate
run: csbt flyway/flywayMigrate
- name: Publish
run: |
csbt docker:publish

3
.gitignore

@ -26,4 +26,5 @@ metals.sbt
assets/
.attach_pid*
hs_err_pid*
*.db
*.db
/app/

1
.scalafix.conf

@ -0,0 +1 @@
rules = [OrganizeImports]

1
README.MD

@ -0,0 +1 @@
Just a scala project for me to experiment with CI and (docker) publishing. Nothing much else to see here.

184
build.sbt

@ -6,21 +6,38 @@ val MunitCatsEffectVersion = "0.13.0"
val FlywayVersion = "7.5.3"
scalaVersion in ThisBuild := "2.13.4"
resolvers in ThisBuild += "jitpack" at "https://jitpack.io"
import com.github.tototoshi.sbt.slick.CodegenPlugin.autoImport.{
slickCodegenDatabasePassword,
slickCodegenDatabaseUrl,
slickCodegenJdbcDriver
}
import _root_.slick.codegen.SourceCodeGenerator
import _root_.slick.{model => m}
import slick.codegen.SourceCodeGenerator
import slick.{model => m}
lazy val databaseUrl = sys.env.getOrElse(
"DB_DEFAULT_URL",
"jdbc:postgresql://localhost:5432/test_db"
)
lazy val databaseUser = sys.env.getOrElse("DB_DEFAULT_USER", "test_user")
lazy val databasePassword = sys.env.getOrElse("DB_DEFAULT_PASSWORD", "password")
lazy val codegenDbHost =
sys.env.getOrElse("HTTP4S_DEMO_CODEGEN_DB_HOST", "localhost")
lazy val codegenDbPort =
sys.env.getOrElse("HTTP4S_DEMO_CODEGEN_DB_PORT", "5432")
lazy val codegenDbName =
sys.env.getOrElse("HTTP4S_DEMO_CODEGEN_DB_NAME", "test_db")
lazy val databaseUrl =
s"jdbc:postgresql://$codegenDbHost:$codegenDbPort/$codegenDbName"
lazy val databaseUser =
sys.env.getOrElse("HTTP4S_DEMO_CODEGEN_DB_USER", "test_user")
lazy val databasePassword =
sys.env.getOrElse("HTTP4S_DEMO_CODEGEN_DB_PASSWORD", "password")
// alpine java docker image for smaller size - "azul/zulu-openjdk-alpine:11-jre-headless"
lazy val dockerJavaImage =
sys.env.getOrElse(
"HTTP4S_DEMO_DOCKER_JAVA_IMAGE",
"openjdk:11-jre-slim-buster"
)
lazy val flyway = (project in file("modules/flyway"))
.enablePlugins(FlywayPlugin)
@ -33,12 +50,39 @@ lazy val flyway = (project in file("modules/flyway"))
flywayBaselineOnMigrate := true
)
lazy val testCommon = (project in file("modules/test-common"))
.settings(
libraryDependencies ++= Seq(
"com.github.monix" % "monix-bio" % "0a2ad29275",
"com.github.valskalla" %% "odin-monix" % "0.9.1",
"de.lolhens" %% "munit-tagless-final" % "0.0.1"
)
)
lazy val root = (project in file("."))
.enablePlugins(CodegenPlugin)
.enablePlugins(
CodegenPlugin,
DockerPlugin,
JavaAppPackaging,
AshScriptPlugin,
BuildInfoPlugin,
GitBranchPrompt
)
.configs(IntegrationTest)
.settings(
organization := "wow.doge",
name := "http4s-demo",
version := "0.0.1-SNAPSHOT",
version in Docker := sys.env
.get("HTTP4S_DEMO_DOCKER_PUBLISH_TAG")
.map(s => if (s.startsWith("v")) s.tail else s)
.getOrElse(version.value),
dockerBaseImage := dockerJavaImage,
dockerExposedPorts := Seq(8081),
dockerUsername := Some("rohansircar"),
Defaults.itSettings,
inConfig(IntegrationTest)(scalafixConfigSettings(IntegrationTest)),
buildInfoOptions ++= Seq(BuildInfoOption.ToJson, BuildInfoOption.BuildTime),
buildInfoPackage := "wow.doge.http4sdemo",
scalacOptions ++= Seq(
"-encoding",
"UTF-8",
@ -56,8 +100,16 @@ lazy val root = (project in file("."))
"-Wconf:cat=lint-byname-implicit:s",
//give errors on non exhaustive matches
"-Wconf:msg=match may not be exhaustive:e",
// """-Wconf:site=wow\.doge\.http4sdemo\.slickcodegen\Tables\$:i""",
"-Wconf:msg=early initializers are deprecated:i",
"""-Wconf:site=wow\.doge\.http4sdemo\.slickcodegen\..*:i""",
// """-Wconf:src=target/src_managed/Tables.scala:s""",
"-explaintypes" // Explain type errors in more detail.
),
scalacOptions ++= {
if (insideCI.value) Seq("-Xfatal-warnings")
else Seq.empty
},
javacOptions ++= Seq("-source", "11", "-target", "11"),
//format: off
libraryDependencies ++= Seq(
@ -66,16 +118,17 @@ lazy val root = (project in file("."))
"org.http4s" %% "http4s-circe" % Http4sVersion,
"org.http4s" %% "http4s-dsl" % Http4sVersion,
"io.circe" %% "circe-generic" % CirceVersion,
"org.scalameta" %% "munit" % MunitVersion % Test,
"org.typelevel" %% "munit-cats-effect-2" % MunitCatsEffectVersion % Test,
"org.scalameta" %% "munit" % MunitVersion % "it,test",
"org.typelevel" %% "munit-cats-effect-2" % MunitCatsEffectVersion % "it,test",
"ch.qos.logback" % "logback-classic" % LogbackVersion,
"org.scalameta" %% "svm-subs" % "20.2.0",
"co.fs2" %% "fs2-reactive-streams" % "2.5.0"
"co.fs2" %% "fs2-reactive-streams" % "2.5.0",
),
//format: on
libraryDependencies ++= Seq(
"io.monix" %% "monix" % "3.3.0",
"io.monix" %% "monix-bio" % "1.1.0",
// "io.monix" %% "monix-bio" % "1.1.0",
"com.github.monix" % "monix-bio" % "0a2ad29275",
"io.circe" %% "circe-core" % "0.13.0",
"io.circe" %% "circe-generic" % "0.13.0",
"com.softwaremill.sttp.client" %% "core" % "2.2.9",
@ -103,52 +156,27 @@ lazy val root = (project in file("."))
"com.github.pureconfig" %% "pureconfig" % "0.14.0",
"io.scalaland" %% "chimney" % "0.6.0",
"com.rms.miu" %% "slick-cats" % "0.10.4",
"com.kubukoz" %% "slick-effect" % "0.3.0"
),
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.10.3"),
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1"),
ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.4.3",
inThisBuild(
List(
scalaVersion := scalaVersion.value, // 2.11.12, or 2.13.3
semanticdbEnabled := true, // enable SemanticDB
semanticdbVersion := "4.4.2" // use Scalafix compatible version
)
"com.kubukoz" %% "slick-effect" % "0.3.0",
"io.circe" %% "circe-fs2" % "0.13.0",
// "org.scalameta" %% "munit" % "0.7.23" % "it,test",
"de.lolhens" %% "munit-tagless-final" % "0.0.1" % "it,test",
"org.scalameta" %% "munit-scalacheck" % "0.7.23" % "it,test",
"org.scalacheck" %% "scalacheck" % "1.15.3" % "it,test",
"com.dimafeng" %% "testcontainers-scala-munit" % "0.39.3" % IntegrationTest,
"com.dimafeng" %% "testcontainers-scala-postgresql" % "0.39.3" % IntegrationTest
),
testFrameworks += new TestFramework("munit.Framework"),
assemblyMergeStrategy in assembly := {
case PathList("javax", "servlet", xs @ _*) => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
case "application.conf" => MergeStrategy.concat
case "unwanted.txt" => MergeStrategy.discard
case x if Assembly.isConfigFile(x) =>
MergeStrategy.concat
case PathList("META-INF", xs @ _*) =>
(xs map { _.toLowerCase }) match {
case ("manifest.mf" :: Nil) | ("index.list" :: Nil) |
("dependencies" :: Nil) =>
MergeStrategy.discard
case ps @ (x :: xs)
if ps.last.endsWith(".sf") || ps.last.endsWith(".dsa") =>
MergeStrategy.discard
case "plexus" :: xs =>
MergeStrategy.discard
case "services" :: xs =>
MergeStrategy.filterDistinctLines
case ("spring.schemas" :: Nil) | ("spring.handlers" :: Nil) =>
MergeStrategy.filterDistinctLines
case _ => MergeStrategy.first // Changed deduplicate to first
}
case PathList(_*) => MergeStrategy.first
}
buildInfoKeys := Seq[BuildInfoKey](
name,
version,
scalaVersion,
sbtVersion,
libraryDependencies,
javacOptions,
dockerBaseImage
)
)
.settings(
// libraryDependencies ++= Seq(
// "com.zaxxer" % "HikariCP" % "3.4.2",
// "com.typesafe.slick" %% "slick" % "3.3.2",
// "com.typesafe.slick" %% "slick-hikaricp" % "3.3.2",
// "com.h2database" % "h2" % "1.4.199"
// ),
slickCodegenDatabaseUrl := databaseUrl,
slickCodegenDatabaseUser := databaseUser,
slickCodegenDatabasePassword := databasePassword,
@ -159,10 +187,13 @@ lazy val root = (project in file("."))
slickCodegenCodeGenerator := { (model: m.Model) =>
new SourceCodeGenerator(model) {
override def Table = new Table(_) {
// override def EntityType = new EntityType {
// override def caseClassFinal = true
// }
override def Column = new Column(_) {
override def rawType = model.tpe match {
case "java.sql.Timestamp" =>
"java.time.Instant" // kill j.s.Timestamp
"java.time.LocalDateTime" // kill j.s.Timestamp
case _ =>
super.rawType
}
@ -172,4 +203,41 @@ lazy val root = (project in file("."))
},
sourceGenerators in Compile += slickCodegen.taskValue
)
.dependsOn(flyway)
.dependsOn(flyway, testCommon)
ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.4.3"
inThisBuild(
List(
scalaVersion := scalaVersion.value, // 2.11.12, or 2.13.3
semanticdbEnabled := true, // enable SemanticDB
semanticdbVersion := "4.4.2", // use Scalafix compatible version
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.10.3"),
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1"),
dynverSeparator := "-"
)
)
addCommandAlias("lint-check", "scalafmtCheckAll; scalafixAll --check")
addCommandAlias("lint-run", "scalafmtAll; scalafixAll")
wartremoverErrors in (Compile, compile) ++=
Warts.allBut(
Wart.Any,
Wart.NonUnitStatements,
Wart.StringPlusAny,
Wart.Overloading,
Wart.PublicInference,
Wart.Nothing,
Wart.Var,
Wart.DefaultArguments,
Wart.OptionPartial,
// Wart.MutableDataStructures,
Wart.ImplicitConversion,
Wart.ImplicitParameter,
Wart.ToString,
Wart.Recursion,
Wart.While,
Wart.ExplicitImplicitTypes,
Wart.ListUnapply
)
wartremoverExcluded += (sourceManaged in Compile).value

BIN
lib/monix-bio_2.13.jar

6
modules/flyway/src/main/resources/db/migration/default/V1__create_users_table.sql

@ -1,6 +0,0 @@
create table "users" (
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
"email" VARCHAR(1024) NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NULL
);

36
modules/flyway/src/main/resources/db/migration/default/V1__library_schema.sql

@ -0,0 +1,36 @@
create table authors (
author_id SERIAL PRIMARY KEY,
author_name VARCHAR(30) NOT NULL
);
CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
isbn VARCHAR(50) UNIQUE NOT NULL,
book_title VARCHAR(30) NOT NULL,
author_id INTEGER REFERENCES authors(author_id) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
create table books_store (
books_store_id SERIAL PRIMARY KEY,
book_id INTEGER REFERENCES books(book_id) NOT NULL,
quantity INTEGER NOT NULL
);
create table book_expiry (
book_expiry_id SERIAL PRIMARY KEY,
book_id INTEGER REFERENCES books(book_id) NOT NULL,
discontinued BOOLEAN NOT NULL
);
create table users (
user_id SERIAL PRIMARY KEY NOT NULL,
user_name VARCHAR(30) NOT NULL
);
create table checkouts (
checkout_id SERIAL PRIMARY KEY,
book_id INTEGER REFERENCES books(book_id) NOT NULL,
taken_by INTEGER REFERENCES users(user_id) NOT NULL,
return_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);

6
modules/flyway/src/main/resources/db/migration/default/V2__add_user.sql

@ -1,6 +0,0 @@
INSERT INTO "users" VALUES (
'd074bce8-a8ca-49ec-9225-a50ffe83dc2f',
'myuser@example.com',
(TIMESTAMP '2013-03-26T17:50:06Z'),
(TIMESTAMP '2013-03-26T17:50:06Z')
);

69
modules/flyway/src/main/resources/db/migration/default/V2__sample_data.sql

@ -0,0 +1,69 @@
insert into
authors (author_name)
values
('Author1');
insert into
authors (author_name)
values
('Author2');
insert into
authors (author_name)
values
('Author3');
insert into
books (isbn, book_title, author_id)
values
('aebwegbwe', 'book1', 3);
insert into
books (isbn, book_title, author_id)
values
('abeqegbqeg', 'book2', 2);
insert into
books (isbn, book_title, author_id)
values
('aebhqeqegq', 'book3', 1);
insert into
books_store (book_id, quantity)
values
(1, 5);
insert into
books_store (book_id, quantity)
values
(2, 3);
insert into
books_store (book_id, quantity)
values
(3, 8);
insert into
book_expiry (book_id, discontinued)
values
(1, false);
insert into
book_expiry (book_id, discontinued)
values
(2, false);
insert into
book_expiry (book_id, discontinued)
values
(3, false);
insert into
users (user_name)
values
('user1');
insert into
users (user_name)
values
('user2');

6
modules/flyway/src/main/resources/db/migration/default/V3__create_cars_table.sql

@ -1,6 +0,0 @@
create table "cars" (
"id" VARCHAR(255) PRIMARY KEY NOT NULL,
"model" VARCHAR(1024) NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NULL
);

6
modules/flyway/src/main/resources/db/migration/default/V4__add_car.sql

@ -1,6 +0,0 @@
INSERT INTO "cars" VALUES (
'd074bce8-a8ca-49ec-9225-a50ffe83dc2f',
'gxxer',
(TIMESTAMP '2013-03-26T17:50:06Z'),
(TIMESTAMP '2013-03-26T17:50:06Z')
);

12
modules/flyway/src/main/resources/db/migration/default/V5__authors_books_table.sql

@ -1,12 +0,0 @@
create table authors (
id SERIAL PRIMARY KEY,
name VARCHAR(15) NOT NULL
);
create table books (
id SERIAL PRIMARY KEY,
title VARCHAR(50) NOT NULL,
author_id INTEGER NOT NULL,
FOREIGN KEY(author_id) REFERENCES authors(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);

14
modules/flyway/src/main/resources/db/migration/default/V6__insert_books_and_authors.sql

@ -1,14 +0,0 @@
-- create table authors (
-- id INTEGER PRIMARY KEY NOT NULL,
-- name VARCHAR(15)
-- );
-- create table books (
-- id INTEGER PRIMARY KEY NOT NULL,
-- title VARCHAR(15) NOT NULL,
-- author_id INTEGER NOT NULL,
-- FOREIGN KEY(author_id) REFERENCES authors(id)
-- );
INSERT INTO authors (name) VALUES ('Jane Austen');
INSERT INTO books (title, author_id) VALUES ('Pride and Prejudice', 1);

26
modules/test-common/src/main/scala/wow/doge/MonixBioSuite.scala

@ -0,0 +1,26 @@
package wow.doge.http4sdemo
import scala.concurrent.Future
import cats.syntax.all._
import io.odin.Logger
import io.odin.fileLogger
import io.odin.syntax._
import monix.bio.Task
import monix.execution.Scheduler
import munit.TestOptions
import java.time.LocalDateTime
trait MonixBioSuite extends munit.TaglessFinalSuite[Task] {
override protected def toFuture[A](f: Task[A]): Future[A] = {
implicit val s = Scheduler.global
f.runToFuture
}
val date = LocalDateTime.now()
val noopLogger = Logger.noop[Task]
val consoleLogger = io.odin.consoleLogger[Task]()
}

13
project/plugins.sbt

@ -1,12 +1,15 @@
// addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.14")
addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10")
// https://github.com/tototoshi/sbt-slick-codegen
libraryDependencies += "com.h2database" % "h2" % "1.4.196"
libraryDependencies += "org.postgresql" % "postgresql" % "42.2.18"
addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1")
addSbtPlugin("com.github.tototoshi" % "sbt-slick-codegen" % "1.4.0")
// Database migration
// https://github.com/flyway/flyway-sbt
addSbtPlugin("io.github.davidmweber" % "flyway-sbt" % "7.4.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.23")
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.8.0")
addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.1.1")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0")
addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.4.13")

5
scripts/.env

@ -0,0 +1,5 @@
export POSTGRES_DB=codegen_db
export CODEGEN_DB_HOST=localhost
export CODEGEN_DB_NAME=codegen_db
export CODEGEN_DB_USER=codegen_user
export CODEGEN_DB_PASSWORD=password

46
scripts/app.Dockerfile

@ -0,0 +1,46 @@
FROM scala/coursier-sbt:0.0.2
ARG DOCKER_TAG
# RUN apt-get update
# RUN apt-get -y install git
# RUN apt-get -y install curl
# RUN sh -c '(echo "#!/usr/bin/env sh" && curl -fLo cs https://git.io/coursier-cli-"$(uname | tr LD ld)") && chmod +x cs'
# RUN ./cs install cs
# ENV PATH=${PATH}:/root/.local/share/coursier/bin
# RUN export PATH="$PATH:/root/.local/share/coursier/bin"
# RUN rm ./cs
# ENV PATH=${PATH}:/root/.local/share/coursier/bin
# RUN export PATH="$PATH:/root/.local/share/coursier/bin"
# RUN mkdir -p /root/.local/share/coursier
# COPY coursier/bin /root/.local/share/coursier/bin
# RUN echo $PATH
# RUN cs install sbt
RUN mkdir -p /usr/src/app/bin
WORKDIR /usr/src/app
COPY ./ /usr/src/app
# RUN cat /etc/hosts
# COPY wait-for-it.sh wait-for-it.sh
# RUN chmod +x wait-for-it.sh
# ENTRYPOINT [ "/bin/bash", "-c" ]
# CMD ["./wait-for-it.sh" , "project_db:5432" , "--strict" , "--timeout=30000" , "--" , "echo 'db has started'"]
# RUN bash ./wait-for-it.sh project_db:5432 --timeout=3000 --strict -- echo "db is up"
# RUN cat /etc/hosts
# CMD [ "sbt" , "flyway/flywayMigrate" ]
# CMD ["sbtn","universal:packageBin"]
# CMD sh sbtn flyway/flywayMigrate; sbtn universal:packageBin
# RUN sbt flyway/flywayMigrate
# RUN sbt docker:stage
CMD sh Docker/app.sh
# CMD ["coursier", "--help"]
# RUN coursier install sbt
# RUN sbt docker:stage
# RUN

7
scripts/app.sh

@ -0,0 +1,7 @@
sbtn flyway/flywayMigrate
sbtn universal:packageZipTarball
tar -xf target/universal/http4s-demo-0.0.1-SNAPSHOT.tgz -C bin
# ./http4s-demo-0.0.1-SNAPSHOT/bin/http4s-demo
# sbtn docker:stage
# mv targer/docker/** bin
rm -r target

24
scripts/build.sh

@ -0,0 +1,24 @@
# export POSTGRES_DB=codegen_db
export CODEGEN_DB_HOST=localhost
export CODEGEN_DB_NAME=codegen_db
export CODEGEN_DB_USER=codegen_user
export CODEGEN_DB_PASSWORD=password
export CODEGEN_DB_PORT=5435
cid=$(docker run \
-e POSTGRES_DB=$CODEGEN_DB_NAME \
-e POSTGRES_USER=$CODEGEN_DB_USER \
-e POSTGRES_PASSWORD=$CODEGEN_DB_PASSWORD \
-p $CODEGEN_DB_PORT:5432 \
-d postgres:12)
echo "Container id is $cid"
sleep 5s
# ./wait-for-it.sh localhost:5434 -s -t 300 -- echo "db started"
sbtn flyway/flywayMigrate
# needs docker login
sbtn docker:publish
sbtn shutdown
docker stop $cid
docker rm $cid

7
scripts/curl

@ -0,0 +1,7 @@
curl -X POST -H "content-type: application/json" http://localhost:8081/api/post/book --data '{"aege":"aaegqE"}'
curl http://localhost:8081/api/get/books
curl http://localhost:8081/api/get/book/1
curl -X POST -H "content-type: application/json" http://localhost:8081/api/post/book --data '{"title":"aaegqE", "authorId": 1}'
curl -X PATCH -H "content-type: application/json" http://localhost:8081/api/update/book/2 --data '{"title":"abwbewe"}'

4
scripts/db.Dockerfile

@ -0,0 +1,4 @@
FROM postgres:12
ENV POSTGRES_USER test_user
ENV POSTGRES_PASSWORD password
ENV POSTGRES_DB test_db

6
scripts/db.sh

@ -0,0 +1,6 @@
docker run \
-e POSTGRES_DB=test_db \
-e POSTGRES_USER=test_user \
-e POSTGRES_PASSWORD=password \
-p 5433:5432 \
-d postgres:12

41
scripts/docker-compose.yml

@ -0,0 +1,41 @@
version: "3.3"
services:
db:
container_name: project_db
image: postgres:12
# build:
# context: ./Docker
# dockerfile: db.Dockerfile
environment:
POSTGRES_DB: 'codegen_db'
POSTGRES_USER: 'codegen_user'
POSTGRES_PASSWORD: 'password'
# volumes:
# - ./var/pgdata:/var/lib/postgresql/data
ports:
- "5432:5433"
# network_mode: host
backend:
container_name: project_backend
build:
context: .
dockerfile: app.Dockerfile
# ports:
# - "9000:9001"
environment:
POSTGRES_DB: 'codegen_db'
CODEGEN_DB_HOST: 'project_db'
CODEGEN_DB_NAME: 'codegen_db'
CODEGEN_DB_USER: 'codegen_user'
CODEGEN_DB_PASSWORD: 'password'
volumes:
- ./app:/usr/src/app/bin
# links:
# - db
# # command: ["./wait-for-it.sh", "project_db:5432", "--strict" , "--timeout=30000" , "--" , "echo 'db has started'"]
# depends_on:
# - db
# # condition: service_healthy

11
scripts/native

@ -0,0 +1,11 @@
native-image --trace-class-initialization --static -H:+ReportExceptionStackTraces -H:+AddAllCharsets --allow-incomplete-classpath --no-fallback --initialize-at-build-time --enable-http --enable-https --enable-all-security-services --initialize-at-run-time=org.flywaydb.core.internal.scanner.cloud.s3.AwsS3Scanner \
--initialize-at-run-time=org.flywaydb.core.internal.scanner.classpath.jboss.JBossVFSv3ClassPathLocationScanner \
--initialize-at-run-time=org.postgresql.sspi.SSPIClient \
--initialize-at-build-time=scala.runtime.Statics$VM \
--initialize-at-run-time=scala.tools.nsc.profile.ExtendedThreadMxBean \
--verbose -jar "./target/scala-2.13/http4s-demo-assembly-0.0.1-SNAPSHOT.jar" http4s-demoBinaryImage
--initialize-at-run-time=scala.tools.nsc.profile.ExtendedThreadMxBean \
--initialize-at-build-time=scala.tools.nsc.profile.SunThreadMxBean \

0
native-image-readme.md → scripts/native-image-readme.md

4
scripts/test.Dockerfile

@ -0,0 +1,4 @@
FROM scala/coursier/sbt:v0.0.1
# RUN apt search docker
RUN apt install -y docker.io
RUN docker --help

182
scripts/wait-for-it.sh

@ -0,0 +1,182 @@
#!/usr/bin/env bash
# Use this script to test if a given TCP host/port are available
WAITFORIT_cmdname=${0##*/}
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
usage()
{
cat << USAGE >&2
Usage:
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit 1
}
wait_for()
{
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
else
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
fi
WAITFORIT_start_ts=$(date +%s)
while :
do
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
WAITFORIT_result=$?
else
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
WAITFORIT_result=$?
fi
if [[ $WAITFORIT_result -eq 0 ]]; then
WAITFORIT_end_ts=$(date +%s)
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
break
fi
sleep 1
done
return $WAITFORIT_result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
# process arguments
while [[ $# -gt 0 ]]
do
case "$1" in
*:* )
WAITFORIT_hostport=(${1//:/ })
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
shift 1
;;
--child)
WAITFORIT_CHILD=1
shift 1
;;
-q | --quiet)
WAITFORIT_QUIET=1
shift 1
;;
-s | --strict)
WAITFORIT_STRICT=1
shift 1
;;
-h)
WAITFORIT_HOST="$2"
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
shift 2
;;
--host=*)
WAITFORIT_HOST="${1#*=}"
shift 1
;;
-p)
WAITFORIT_PORT="$2"
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
shift 2
;;
--port=*)
WAITFORIT_PORT="${1#*=}"
shift 1
;;
-t)
WAITFORIT_TIMEOUT="$2"
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
shift 2
;;
--timeout=*)
WAITFORIT_TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
WAITFORIT_CLI=("$@")
break
;;
--help)
usage
;;
*)
echoerr "Unknown argument: $1"
usage
;;
esac
done
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
echoerr "Error: you need to provide a host and port to test."
usage
fi
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
# Check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
wait_for
WAITFORIT_RESULT=$?
exit $WAITFORIT_RESULT
else
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
wait_for_wrapper
WAITFORIT_RESULT=$?
else
wait_for
WAITFORIT_RESULT=$?
fi
fi
if [[ $WAITFORIT_CLI != "" ]]; then
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
exit $WAITFORIT_RESULT
fi
exec "${WAITFORIT_CLI[@]}"
else
exit $WAITFORIT_RESULT
fi

10
src/it/resources/logback-test.xml

@ -0,0 +1,10 @@
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="error">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

112
src/it/scala/wow/doge/http4sdemo/DatabaseIntegrationTestBase.scala

@ -0,0 +1,112 @@
package wow.doge.http4sdemo
import com.dimafeng.testcontainers.ContainerDef
import com.dimafeng.testcontainers.PostgreSQLContainer
import com.dimafeng.testcontainers.munit.TestContainerForAll
import com.typesafe.config.ConfigFactory
import monix.bio.IO
import monix.bio.Task
import monix.bio.UIO
import monix.execution.Scheduler
import org.testcontainers.utility.DockerImageName
import slick.jdbc.JdbcBackend
import slick.jdbc.PostgresProfile
import wow.doge.http4sdemo.MonixBioSuite
trait DatabaseIntegrationTestBase
extends MonixBioSuite
with TestContainerForAll {
def databaseName = "testcontainer-scala"
def username = "scala"
def password = "scala"
override val containerDef: ContainerDef = PostgreSQLContainer.Def(
dockerImageName = DockerImageName.parse("postgres:12-alpine"),
databaseName = databaseName,
username = username,
password = password
)
lazy val profile = PostgresProfile
def config(url: String) = ConfigFactory.parseString(s"""|
|testDatabase = {
| url = "$url"
| driver = org.postgresql.Driver
| user = $username
| password = $password
|
| numThreads = 2
|
| queueSize = 10
|
| maxThreads = 2
|
| maxConnections = 2
|
}""".stripMargin)
def withDb[T](url: String)(f: JdbcBackend.DatabaseDef => Task[T]) = Task(
// JdbcBackend.Database.forURL(
// url,
// // user = username,
// // password = password,
// // driver = "org.postgresql.Driver",
// prop = Map(
// "driver" -> "org.postgresql.Driver",
// "user" -> username,
// "password" -> password,
// "numThreads" -> "16",
// "maxThreads" -> "36",
// "queueSize" -> "10",
// "maxConnections" -> "36"
// )
// )
JdbcBackend.Database.forConfig("testDatabase", config(url))
).bracket(f)(db => UIO(db.close()))
def createSchema(containers: Containers) = {
implicit val s = Scheduler.global
containers match {
case container: PostgreSQLContainer =>
val config = JdbcDatabaseConfig(
container.jdbcUrl,
"org.postgresql.Driver",
Some(username),
Some(password),
"flyway_schema_history",
List("classpath:db/migration/default")
)
// (UIO(println("creating db")) >> dbBracket(container.jdbcUrl)(
// // _.runL(Tables.schema.create)
// _ => DBMigrations.migrate[Task](config)
// ))
DBMigrations.migrate[Task](config).runSyncUnsafe(munitTimeout)
case _ => ()
}
}
// val fixture = ResourceFixture(
// Resource.make(
// Task(
// JdbcBackend.Database.forURL(
// "jdbc:postgresql://localhost:49162/testcontainer-scala?",
// user = username,
// password = password,
// driver = "org.postgresql.Driver"
// )
// )
// )(db => Task(db.close()))
// )
def withContainersIO[A](pf: PartialFunction[Containers, Task[A]]): Task[A] = {
withContainers { containers =>
pf.applyOrElse(
containers,
(c: Containers) =>
IO.terminate(new Exception(s"Unknown container: ${c.toString}"))
)
}
}
}

121
src/it/scala/wow/doge/http4sdemo/LibraryServiceSpec.scala

@ -0,0 +1,121 @@
package wow.doge.http4sdemo
import com.dimafeng.testcontainers.PostgreSQLContainer
import monix.bio.UIO
import wow.doge.http4sdemo.dto.BookSearchMode
import wow.doge.http4sdemo.dto.NewAuthor
import wow.doge.http4sdemo.dto.NewBook
import wow.doge.http4sdemo.implicits._
import wow.doge.http4sdemo.services.LibraryDbio
import wow.doge.http4sdemo.services.LibraryService
import wow.doge.http4sdemo.services.LibraryServiceImpl
class LibraryServiceSpec extends DatabaseIntegrationTestBase {
override def afterContainersStart(containers: Containers): Unit = {
super.afterContainersStart(containers)
createSchema(containers)
}
test("insert and retrieve book") {
withContainersIO { case container: PostgreSQLContainer =>
val io =
withDb(container.jdbcUrl)(db =>
for {
_ <- UIO.unit
service: LibraryService = new LibraryServiceImpl(
profile,
new LibraryDbio(profile),
db
)
id <- service.insertAuthor(NewAuthor("author1"))
book <- service.insertBook(NewBook("blah", "Segehwe", id))
_ <- service
.getBookById(book.bookId)
.assertEquals(Some(book))
} yield ()
)
io
}
}
test("author does not exist error on book insertion") {
withContainersIO { case container: PostgreSQLContainer =>
val io =
withDb(container.jdbcUrl)(db =>
for {
_ <- UIO.unit
service: LibraryService = new LibraryServiceImpl(
profile,
new LibraryDbio(profile),
db
)
_ <- service
.insertBook(NewBook("blah2", "agege", 23))
.attempt
.assertEquals(
Left(
LibraryService
.EntityDoesNotExist("Author with id=23 does not exist")
)
)
} yield ()
)
io
}
}
test("books with isbn already exists error on book insertion") {
withContainersIO { case container: PostgreSQLContainer =>
val io =
withDb(container.jdbcUrl)(db =>
for {
_ <- UIO.unit
service: LibraryService = new LibraryServiceImpl(
profile,
new LibraryDbio(profile),
db
)
_ <- service.insertBook(NewBook("blah2", "agege", 1))
_ <- service
.insertBook(NewBook("blah3", "agege", 1))
.attempt
.assertEquals(
Left(
LibraryService
.EntityAlreadyExists("Book with isbn=agege already exists")
)
)
} yield ()
)
io
}
}
test("search books by author id") {
withContainersIO { case container: PostgreSQLContainer =>
val io =
withDb(container.jdbcUrl)(db =>
for {
_ <- UIO.unit
service: LibraryService = new LibraryServiceImpl(
profile,
new LibraryDbio(profile),
db
)
id <- service.insertAuthor(NewAuthor("bar"))
book1 <- service.insertBook(NewBook("blah3", "aeaega", id))
book2 <- service.insertBook(NewBook("blah4", "afgegg", id))
_ <- service
.searchBook(BookSearchMode.AuthorName, "bar")
.toListL
.toIO
.attempt
.assertEquals(Right(List(book1, book2)))
} yield ()
)
io
}
}
}

22
src/main/resources/META-INF/native-image/wow/doge/http4sdemo/jni-config.json

@ -0,0 +1,22 @@
[
{
"name":"java.lang.ClassLoader",
"methods":[{"name":"getPlatformClassLoader","parameterTypes":[] }]
},
{
"name":"java.lang.NoSuchMethodError"
},
{
"name":"sun.management.VMManagementImpl",
"fields":[
{"name":"compTimeMonitoringSupport"},
{"name":"currentThreadCpuTimeSupport"},
{"name":"objectMonitorUsageSupport"},
{"name":"otherThreadCpuTimeSupport"},
{"name":"remoteDiagnosticCommandsSupport"},
{"name":"synchronizerUsageSupport"},
{"name":"threadAllocatedMemorySupport"},
{"name":"threadContentionMonitoringSupport"}
]
}
]

309
src/main/resources/META-INF/native-image/wow/doge/http4sdemo/reflect-config.json

@ -1,6 +1,5 @@
[
{
"name": "org.slf4j.impl.StaticLoggerBinder",
[{
"name": "org.slf4j.impl.StaticLoggerBinder",
"allDeclaredConstructors": true
},
{
@ -165,16 +164,314 @@
},
{
"name": "ch.qos.logback.classic.encoder.PatternLayoutEncoder",
"allPublicMethods":true,
"allPublicMethods": true,
"allDeclaredConstructors": true
},
{
"name": "ch.qos.logback.core.ConsoleAppender",
"allPublicMethods":true,
"allPublicMethods": true,
"allDeclaredConstructors": true
},
{
"name": "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl",
"allDeclaredConstructors": true
},
{
"name": "com.zaxxer.hikari.HikariConfig",
"allDeclaredFields": true
},
{
"name": "com.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry[]"
},
{
"name": "java.io.FilePermission"
},
{
"name": "java.lang.RuntimePermission"
},
{
"name": "java.lang.String[]"
},
{
"name": "java.lang.invoke.VarHandle",
"methods": [{ "name": "releaseFence", "parameterTypes": [] }]
},
{
"name": "java.lang.reflect.Method[]"
},
{
"name": "java.net.NetPermission"
},
{
"name": "java.net.SocketPermission"
},
{
"name": "java.net.URLPermission",
"methods": [{ "name": "<init>", "parameterTypes": ["java.lang.String", "java.lang.String"] }]
},
{
"name": "java.nio.ByteBuffer[]"
},
{
"name": "java.security.AlgorithmParametersSpi"
},
{
"name": "java.security.AllPermission"
},
{
"name": "java.security.KeyStoreSpi"
},
{
"name": "java.security.MessageDigestSpi"
},
{
"name": "java.security.SecureRandomParameters"
},
{
"name": "java.security.SecurityPermission"
},
{
"name": "java.sql.Statement[]"
},
{
"name": "java.util.PropertyPermission"
},
{
"name": "javax.management.ObjectName"
},
{
"name": "javax.security.auth.x500.X500Principal",
"fields": [{ "name": "thisX500Name" }],
"methods": [{ "name": "<init>", "parameterTypes": ["sun.security.x509.X500Name"] }]
},
{
"name": "monix.execution.internal.atomic.LeftRight128Java8BoxedObjectImpl",
"fields": [{ "name": "value", "allowUnsafeAccess": true }]
},
{
"name": "monix.execution.internal.atomic.NormalJava8BoxedInt",
"fields": [{ "name": "value", "allowUnsafeAccess": true }]
},
{
"name": "monix.execution.internal.atomic.NormalJava8BoxedObject",
"fields": [{ "name": "value", "allowUnsafeAccess": true }]
},
{
"name": "org.flywaydb.core.api.Location[]"
},
{
"name": "org.flywaydb.core.internal.logging.slf4j.Slf4jLogCreator",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "org.h2.Driver"
},
{
"name": "org.http4s.blaze.channel.nio1.SelectorLoop[]"
},
{
"name": "org.http4s.blaze.util.TickWheelExecutor$Bucket[]"
},
{
"name": "org.postgresql.Driver",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "org.postgresql.PGProperty",
"fields": [
{ "name": "ALLOW_ENCODING_CHANGES" },
{ "name": "APPLICATION_NAME" },
{ "name": "ASSUME_MIN_SERVER_VERSION" },
{ "name": "AUTOSAVE" },
{ "name": "BINARY_TRANSFER" },
{ "name": "BINARY_TRANSFER_DISABLE" },
{ "name": "BINARY_TRANSFER_ENABLE" },
{ "name": "CANCEL_SIGNAL_TIMEOUT" },
{ "name": "CLEANUP_SAVEPOINTS" },
{ "name": "CONNECT_TIMEOUT" },
{ "name": "CURRENT_SCHEMA" },
{ "name": "DATABASE_METADATA_CACHE_FIELDS" },
{ "name": "DATABASE_METADATA_CACHE_FIELDS_MIB" },
{ "name": "DEFAULT_ROW_FETCH_SIZE" },
{ "name": "DISABLE_COLUMN_SANITISER" },
{ "name": "ESCAPE_SYNTAX_CALL_MODE" },
{ "name": "GSS_ENC_MODE" },
{ "name": "GSS_LIB" },
{ "name": "HIDE_UNPRIVILEGED_OBJECTS" },
{ "name": "HOST_RECHECK_SECONDS" },
{ "name": "JAAS_APPLICATION_NAME" },
{ "name": "JAAS_LOGIN" },
{ "name": "KERBEROS_SERVER_NAME" },
{ "name": "LOAD_BALANCE_HOSTS" },
{ "name": "LOGGER_FILE" },
{ "name": "LOGGER_LEVEL" },
{ "name": "LOGIN_TIMEOUT" },
{ "name": "LOG_SERVER_ERROR_DETAIL" },
{ "name": "LOG_UNCLOSED_CONNECTIONS" },
{ "name": "MAX_RESULT_BUFFER" },
{ "name": "OPTIONS" },
{ "name": "PASSWORD" },
{ "name": "PG_DBNAME" },
{ "name": "PG_HOST" },
{ "name": "PG_PORT" },
{ "name": "PREFER_QUERY_MODE" },
{ "name": "PREPARED_STATEMENT_CACHE_QUERIES" },
{ "name": "PREPARED_STATEMENT_CACHE_SIZE_MIB" },
{ "name": "PREPARE_THRESHOLD" },
{ "name": "PROTOCOL_VERSION" },
{ "name": "READ_ONLY" },
{ "name": "READ_ONLY_MODE" },
{ "name": "RECEIVE_BUFFER_SIZE" },
{ "name": "REPLICATION" },
{ "name": "REWRITE_BATCHED_INSERTS" },
{ "name": "SEND_BUFFER_SIZE" },
{ "name": "SOCKET_FACTORY" },
{ "name": "SOCKET_FACTORY_ARG" },
{ "name": "SOCKET_TIMEOUT" },
{ "name": "SSL" },
{ "name": "SSL_CERT" },
{ "name": "SSL_FACTORY" },
{ "name": "SSL_FACTORY_ARG" },
{ "name": "SSL_HOSTNAME_VERIFIER" },
{ "name": "SSL_KEY" },
{ "name": "SSL_MODE" },
{ "name": "SSL_PASSWORD" },
{ "name": "SSL_PASSWORD_CALLBACK" },
{ "name": "SSL_ROOT_CERT" },
{ "name": "SSPI_SERVICE_CLASS" },
{ "name": "STRING_TYPE" },
{ "name": "TARGET_SERVER_TYPE" },
{ "name": "TCP_KEEP_ALIVE" },
{ "name": "UNKNOWN_LENGTH" },
{ "name": "USER" },
{ "name": "USE_SPNEGO" },
{ "name": "XML_FACTORY_FACTORY" }
]
},
{
"name": "org.slf4j.Logger"
},
{
"name": "org.slf4j.impl.StaticLoggerBinder"
},
{
"name": "scala.Symbol",
"methods": [{ "name": "apply", "parameterTypes": ["java.lang.String"] }]
},
{
"name": "scala.concurrent.BlockContext$",
"allDeclaredMethods": true
},
{
"name": "scala.util.Either[]"
},
{
"name": "slick.jdbc.hikaricp.HikariCPJdbcDataSource$",
"fields": [{ "name": "MODULE$" }]
},
{
"name": "slick.relational.ResultConverter[]"
},
{
"name": "sun.misc.Unsafe",
"fields": [{ "name": "theUnsafe" }],
"methods": [
{ "name": "fullFence", "parameterTypes": [] },
{ "name": "getAndAddInt", "parameterTypes": ["java.lang.Object", "long", "int"] },
{ "name": "getAndAddLong", "parameterTypes": ["java.lang.Object", "long", "long"] },
{ "name": "getAndSetObject", "parameterTypes": ["java.lang.Object", "long", "java.lang.Object"] }
]
},
{
"name": "sun.security.pkcs12.PKCS12KeyStore",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.provider.JavaKeyStore$JKS",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.provider.MD5",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.provider.NativePRNG",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.provider.SHA",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.provider.X509Factory",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.rsa.RSAKeyFactory$Legacy",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.ssl.KeyManagerFactoryImpl$SunX509",
"methods": [{ "name": "<init>", "parameterTypes": [] }]
},
{
"name": "sun.security.ssl.SSLContextImpl$DefaultSSLContext",