diff --git a/app-server/subprojects/bounded_context/external_accessibility/application/build.gradle.kts b/app-server/subprojects/bounded_context/external_accessibility/application/build.gradle.kts new file mode 100644 index 000000000..e92018024 --- /dev/null +++ b/app-server/subprojects/bounded_context/external_accessibility/application/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies { + implementation(projects.apiSpecification.domainEvent) +} diff --git a/app-server/subprojects/bounded_context/external_accessibility/application/src/main/kotlin/club/staircrusher/external_accessibility/application/port/out/ExternalAccessibilityRepository.kt b/app-server/subprojects/bounded_context/external_accessibility/application/src/main/kotlin/club/staircrusher/external_accessibility/application/port/out/ExternalAccessibilityRepository.kt new file mode 100644 index 000000000..8eef6006b --- /dev/null +++ b/app-server/subprojects/bounded_context/external_accessibility/application/src/main/kotlin/club/staircrusher/external_accessibility/application/port/out/ExternalAccessibilityRepository.kt @@ -0,0 +1,7 @@ +package club.staircrusher.external_accessibility.application.port.out.persistence + +import club.staircrusher.external_accessibility.domain.model.ExternalAccessibility +import club.staircrusher.stdlib.domain.repository.EntityRepository + +@Suppress("TooManyFunctions") +interface ExternalAccessibilityRepository : EntityRepository {} diff --git a/app-server/subprojects/bounded_context/external_accessibility/domain/build.gradle.kts b/app-server/subprojects/bounded_context/external_accessibility/domain/build.gradle.kts new file mode 100644 index 000000000..7d82dc72f --- /dev/null +++ b/app-server/subprojects/bounded_context/external_accessibility/domain/build.gradle.kts @@ -0,0 +1,2 @@ +dependencies { +} diff --git a/app-server/subprojects/bounded_context/external_accessibility/domain/src/main/kotlin/club/staircrusher/external_accessibility/domain/model/ExternalAccessibility.kt b/app-server/subprojects/bounded_context/external_accessibility/domain/src/main/kotlin/club/staircrusher/external_accessibility/domain/model/ExternalAccessibility.kt new file mode 100644 index 000000000..fb2392b1b --- /dev/null +++ b/app-server/subprojects/bounded_context/external_accessibility/domain/src/main/kotlin/club/staircrusher/external_accessibility/domain/model/ExternalAccessibility.kt @@ -0,0 +1,13 @@ +package club.staircrusher.external_accessibility.domain.model + +import java.time.Instant + +data class ExternalAccessibility( + val id: String, + val name: String, + val latitude: Double, + val longitude: Double, + val address: String, + val createdAt: Instant, + val updatedAt: Instant, +) diff --git a/app-server/subprojects/bounded_context/external_accessibility/infra/build.gradle.kts b/app-server/subprojects/bounded_context/external_accessibility/infra/build.gradle.kts new file mode 100644 index 000000000..ae9ad5ca8 --- /dev/null +++ b/app-server/subprojects/bounded_context/external_accessibility/infra/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("io.spring.dependency-management") + id("org.springframework.boot") +} + +dependencies { + api(projects.apiSpecification.api) + api(projects.apiSpecification.domainEvent) + implementation(projects.crossCuttingConcern.infra.persistenceModel) + implementation("org.springframework.boot:spring-boot-starter-web") + + integrationTestImplementation(projects.crossCuttingConcern.test.springIt) + + val awsSdkVersion: String by project + implementation("software.amazon.awssdk:s3:$awsSdkVersion") + runtimeOnly("software.amazon.awssdk:sts:$awsSdkVersion") // IRSA를 사용하기 위해서 필요함 + + testImplementation(projects.boundedContext.externalAccessibility.application) +} diff --git a/app-server/subprojects/bounded_context/external_accessibility/infra/src/main/kotlin/club/staircrusher/external_accessibility/infra/adapter/out/persistence/ExternalAccessibilityRepository.kt b/app-server/subprojects/bounded_context/external_accessibility/infra/src/main/kotlin/club/staircrusher/external_accessibility/infra/adapter/out/persistence/ExternalAccessibilityRepository.kt new file mode 100644 index 000000000..c21270ea5 --- /dev/null +++ b/app-server/subprojects/bounded_context/external_accessibility/infra/src/main/kotlin/club/staircrusher/external_accessibility/infra/adapter/out/persistence/ExternalAccessibilityRepository.kt @@ -0,0 +1,39 @@ +package club.staircrusher.external_accessibility.infra.adapter.out.persistence + +import club.staircrusher.external_accessibility.application.port.out.persistence.ExternalAccessibilityRepository +import club.staircrusher.external_accessibility.domain.model.ExternalAccessibility +import club.staircrusher.external_accessibility.infra.adapter.out.persistence.sqldelight.toDomainModel +import club.staircrusher.external_accessibility.infra.adapter.out.persistence.sqldelight.toPersistenceModel +import club.staircrusher.infra.persistence.sqldelight.DB +import club.staircrusher.stdlib.di.annotation.Component + +@Suppress("TooManyFunctions") +@Component +class ExternalAccessibilityRepository( + val db: DB +) : ExternalAccessibilityRepository { + private val queries = db.externalAccessibilityQueries + + override fun findById(id: String): ExternalAccessibility { + return findByIdOrNull(id) ?: throw IllegalArgumentException("ExternalAccessibility of id $id does not exist.") + } + + override fun findByIdOrNull(id: String): ExternalAccessibility? { + return queries.findById(id) + .executeAsOneOrNull() + ?.toDomainModel() + } + + override fun removeAll() { + queries.removeAll() + } + + override fun saveAll(entities: Collection) { + entities.forEach { save(it) } + } + + override fun save(entity: ExternalAccessibility): ExternalAccessibility { + queries.save(entity.toPersistenceModel()) + return entity + } +} diff --git a/app-server/subprojects/bounded_context/external_accessibility/infra/src/main/kotlin/club/staircrusher/external_accessibility/infra/adapter/out/persistence/sqldelight/Converters.kt b/app-server/subprojects/bounded_context/external_accessibility/infra/src/main/kotlin/club/staircrusher/external_accessibility/infra/adapter/out/persistence/sqldelight/Converters.kt new file mode 100644 index 000000000..a79b0c06b --- /dev/null +++ b/app-server/subprojects/bounded_context/external_accessibility/infra/src/main/kotlin/club/staircrusher/external_accessibility/infra/adapter/out/persistence/sqldelight/Converters.kt @@ -0,0 +1,27 @@ +package club.staircrusher.external_accessibility.infra.adapter.out.persistence.sqldelight + +import club.staircrusher.external_accessibility.domain.model.ExternalAccessibility +import club.staircrusher.infra.persistence.sqldelight.migration.External_accessibility +import club.staircrusher.stdlib.time.toOffsetDateTime +import java.time.Instant + + +fun External_accessibility.toDomainModel(): ExternalAccessibility = ExternalAccessibility( + id = id, + name = name, + latitude = location_x, + longitude = location_y, + address = address, + createdAt = created_at.toInstant(), + updatedAt = updated_at.toInstant(), +) + +fun ExternalAccessibility.toPersistenceModel(): External_accessibility = External_accessibility( + id = id, + name = name, + location_x = latitude, + location_y = longitude, + address = address, + created_at = Instant.now().toOffsetDateTime(), + updated_at = Instant.now().toOffsetDateTime(), +) diff --git a/app-server/subprojects/cross_cutting_concern/infra/persistence_model/build.gradle.kts b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/build.gradle.kts index fe720ca68..172233ee4 100644 --- a/app-server/subprojects/cross_cutting_concern/infra/persistence_model/build.gradle.kts +++ b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { implementation(projects.boundedContext.challenge.domain) implementation(projects.boundedContext.quest.domain) implementation(projects.boundedContext.user.domain) + implementation(projects.boundedContext.externalAccessibility.domain) val sqlDelightVersion: String by project api("app.cash.sqldelight:runtime-jvm:$sqlDelightVersion") diff --git a/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/kotlin/club/staircrusher/infra/persistence/sqldelight/DB.kt b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/kotlin/club/staircrusher/infra/persistence/sqldelight/DB.kt index ee1436458..be25d4e93 100644 --- a/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/kotlin/club/staircrusher/infra/persistence/sqldelight/DB.kt +++ b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/kotlin/club/staircrusher/infra/persistence/sqldelight/DB.kt @@ -95,6 +95,7 @@ class DB(dataSource: DataSource) : TransactionManager { val challengeContributionQueries = scc.challengeContributionQueries val challengeParticipationQueries = scc.challengeParticipationQueries val challengeRankQueries = scc.challengeRankQueries + val externalAccessibilityQueries = scc.externalAccessibilityQueries override fun doInTransaction(block: Transaction.() -> T): T { diff --git a/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/sqldelight/club/staircrusher/infra/persistence/sqldelight/migration/V20__external_accessibility.sqm b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/sqldelight/club/staircrusher/infra/persistence/sqldelight/migration/V20__external_accessibility.sqm new file mode 100644 index 000000000..fb14d95c5 --- /dev/null +++ b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/sqldelight/club/staircrusher/infra/persistence/sqldelight/migration/V20__external_accessibility.sqm @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS external_accessibility ( + id VARCHAR(36) NOT NULL, + name VARCHAR(64) NOT NULL, + location_x FLOAT8 NOT NULL, + location_y FLOAT8 NOT NULL, + + address VARCHAR(64) NOT NULL, + created_at TIMESTAMP(6) WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP(6) WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id) +); \ No newline at end of file diff --git a/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/sqldelight/club/staircrusher/infra/persistence/sqldelight/query/external_accessibility/ExternalAccessibility.sq b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/sqldelight/club/staircrusher/infra/persistence/sqldelight/query/external_accessibility/ExternalAccessibility.sq new file mode 100644 index 000000000..450ae31ba --- /dev/null +++ b/app-server/subprojects/cross_cutting_concern/infra/persistence_model/src/main/sqldelight/club/staircrusher/infra/persistence/sqldelight/query/external_accessibility/ExternalAccessibility.sq @@ -0,0 +1,18 @@ +save: +INSERT INTO external_accessibility +VALUES :external_accessibility +ON CONFLICT(id) DO UPDATE SET + name = EXCLUDED.name, + location_x = EXCLUDED.location_x, + location_y = EXCLUDED.location_y, + address = EXCLUDED.address, + created_at = EXCLUDED.created_at, + updated_at = NULL; + +removeAll: +DELETE FROM external_accessibility; + +findById: +SELECT * +FROM external_accessibility +WHERE external_accessibility.id = :id; \ No newline at end of file