diff --git a/build.gradle b/build.gradle
index da384dc69..490688cfb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,7 +42,8 @@ dependencies {
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2',
'io.jsonwebtoken:jjwt-jackson:0.11.2'
implementation 'joda-time:joda-time:2.10.13'
- implementation 'org.xerial:sqlite-jdbc:3.36.0.3'
+ runtimeOnly 'org.xerial:sqlite-jdbc:3.36.0.3'
+ runtimeOnly 'org.postgresql:postgresql'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
@@ -54,6 +55,9 @@ dependencies {
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:2.2.2'
+ testImplementation 'org.testcontainers:testcontainers:1.16.3'
+ testImplementation 'org.testcontainers:postgresql:1.16.3'
+ testImplementation 'org.testcontainers:junit-jupiter:1.16.3'
}
tasks.named('test') {
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 000000000..b844b5443
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,28 @@
+version: '3.8'
+
+services:
+ postgresql:
+ image: postgres:14-alpine
+ environment:
+ POSTGRES_DB: realworld
+ POSTGRES_USER: realworld
+ POSTGRES_PASSWORD: realworld
+ ports:
+ - "5432:5432"
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+ app:
+ build: .
+ ports:
+ - "8080:8080"
+ environment:
+ SPRING_PROFILES_ACTIVE: prod
+ DATABASE_URL: jdbc:postgresql://postgresql:5432/realworld
+ DATABASE_USERNAME: realworld
+ DATABASE_PASSWORD: realworld
+ depends_on:
+ - postgresql
+
+volumes:
+ postgres_data:
diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties
new file mode 100644
index 000000000..34e106e58
--- /dev/null
+++ b/src/main/resources/application-dev.properties
@@ -0,0 +1,6 @@
+spring.datasource.url=jdbc:sqlite:dev.db
+spring.datasource.driver-class-name=org.sqlite.JDBC
+spring.datasource.username=
+spring.datasource.password=
+
+spring.flyway.locations=classpath:db/migration/sqlite
diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties
new file mode 100644
index 000000000..30fb6bfba
--- /dev/null
+++ b/src/main/resources/application-prod.properties
@@ -0,0 +1,6 @@
+spring.datasource.url=${DATABASE_URL:jdbc:postgresql://localhost:5432/realworld}
+spring.datasource.driver-class-name=org.postgresql.Driver
+spring.datasource.username=${DATABASE_USERNAME:realworld}
+spring.datasource.password=${DATABASE_PASSWORD:realworld}
+
+spring.flyway.locations=classpath:db/migration/postgresql
diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties
index 0902f5cba..df0651ec9 100644
--- a/src/main/resources/application-test.properties
+++ b/src/main/resources/application-test.properties
@@ -1 +1,6 @@
-spring.datasource.url=jdbc:sqlite::memory:
\ No newline at end of file
+spring.datasource.url=jdbc:tc:postgresql:14-alpine:///realworld_test
+spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
+spring.datasource.username=test
+spring.datasource.password=test
+
+spring.flyway.locations=classpath:db/migration/postgresql
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 7c1947fc2..6deaf3c07 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,7 +1,5 @@
-spring.datasource.url=jdbc:sqlite:dev.db
-spring.datasource.driver-class-name=org.sqlite.JDBC
-spring.datasource.username=
-spring.datasource.password=
+spring.profiles.active=${SPRING_PROFILES_ACTIVE:dev}
+
spring.jackson.deserialization.UNWRAP_ROOT_VALUE=true
image.default=https://static.productionready.io/images/smiley-cyrus.jpg
diff --git a/src/main/resources/db/migration/postgresql/V1__create_tables.sql b/src/main/resources/db/migration/postgresql/V1__create_tables.sql
new file mode 100644
index 000000000..6145ce7ab
--- /dev/null
+++ b/src/main/resources/db/migration/postgresql/V1__create_tables.sql
@@ -0,0 +1,49 @@
+CREATE TABLE users (
+ id VARCHAR(255) PRIMARY KEY,
+ username VARCHAR(255) UNIQUE,
+ password VARCHAR(255),
+ email VARCHAR(255) UNIQUE,
+ bio TEXT,
+ image VARCHAR(511)
+);
+
+CREATE TABLE articles (
+ id VARCHAR(255) PRIMARY KEY,
+ user_id VARCHAR(255),
+ slug VARCHAR(255) UNIQUE,
+ title VARCHAR(255),
+ description TEXT,
+ body TEXT,
+ created_at TIMESTAMP NOT NULL,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE article_favorites (
+ article_id VARCHAR(255) NOT NULL,
+ user_id VARCHAR(255) NOT NULL,
+ PRIMARY KEY(article_id, user_id)
+);
+
+CREATE TABLE follows (
+ user_id VARCHAR(255) NOT NULL,
+ follow_id VARCHAR(255) NOT NULL
+);
+
+CREATE TABLE tags (
+ id VARCHAR(255) PRIMARY KEY,
+ name VARCHAR(255) NOT NULL
+);
+
+CREATE TABLE article_tags (
+ article_id VARCHAR(255) NOT NULL,
+ tag_id VARCHAR(255) NOT NULL
+);
+
+CREATE TABLE comments (
+ id VARCHAR(255) PRIMARY KEY,
+ body TEXT,
+ article_id VARCHAR(255),
+ user_id VARCHAR(255),
+ created_at TIMESTAMP NOT NULL,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
diff --git a/src/main/resources/db/migration/V1__create_tables.sql b/src/main/resources/db/migration/sqlite/V1__create_tables.sql
similarity index 100%
rename from src/main/resources/db/migration/V1__create_tables.sql
rename to src/main/resources/db/migration/sqlite/V1__create_tables.sql
diff --git a/src/main/resources/mapper/ArticleMapper.xml b/src/main/resources/mapper/ArticleMapper.xml
index 60a9811f6..4b6137df9 100644
--- a/src/main/resources/mapper/ArticleMapper.xml
+++ b/src/main/resources/mapper/ArticleMapper.xml
@@ -45,8 +45,8 @@
T.id tagId,
T.name tagName
from articles A
- left join article_tags AT on A.id = AT.article_id
- left join tags T on T.id = AT.tag_id
+ left join article_tags ATAG on A.id = ATAG.article_id
+ left join tags T on T.id = ATAG.tag_id