Skip to content

Commit a46c601

Browse files
authored
Merge pull request #68 from Project-Unifest/feature/local-database-env-setup
[feat] 관심 부스 로컬 데이터베이스 환경 구축 및 CRUD 연동
2 parents 16e2b41 + 8db68b7 commit a46c601

File tree

56 files changed

+1135
-619
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1135
-619
lines changed

build-logic/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ gradlePlugin {
1616
"android.feature" to "AndroidFeatureConventionPlugin",
1717
"android.hilt" to "AndroidHiltConventionPlugin",
1818
"android.retrofit" to "AndroidRetrofitConventionPlugin",
19-
"jvm.kotlin" to "JvmKotlinConventionPlugin",
20-
"test.kotest" to "TestKotestConventionPlugin",
19+
"android.room" to "AndroidRoomConventionPlugin",
2120
)
2221

2322
plugins {
@@ -45,6 +44,7 @@ kotlin {
4544
dependencies {
4645
compileOnly(libs.gradle.android)
4746
compileOnly(libs.gradle.kotlin)
47+
compileOnly(libs.gradle.androidx.room)
4848

4949
compileOnly(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
5050
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import androidx.room.gradle.RoomExtension
2+
import com.unifest.android.Plugins
3+
import com.unifest.android.applyPlugins
4+
import com.unifest.android.implementation
5+
import com.unifest.android.ksp
6+
import com.unifest.android.libs
7+
import org.gradle.kotlin.dsl.configure
8+
import org.gradle.kotlin.dsl.dependencies
9+
10+
class AndroidRoomConventionPlugin : BuildLogicConventionPlugin(
11+
{
12+
applyPlugins(Plugins.AndroidxRoom, Plugins.KotlinxSerialization, Plugins.Ksp)
13+
14+
extensions.configure<RoomExtension> {
15+
// The schemas directory contains a schema file for each version of the Room database.
16+
// This is required to enable Room auto migrations.
17+
// See https://developer.android.com/reference/kotlin/androidx/room/AutoMigration.
18+
schemaDirectory("$projectDir/schemas")
19+
}
20+
21+
dependencies {
22+
implementation(libs.androidx.room.runtime)
23+
implementation(libs.androidx.room.ktx)
24+
ksp(libs.androidx.room.compiler)
25+
implementation(libs.kotlinx.serialization.json)
26+
}
27+
},
28+
)

build-logic/src/main/kotlin/com/unifest/android/Plugins.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package com.unifest.android
22

33
internal object Plugins {
4-
const val JavaLibrary = "java-library"
5-
6-
const val KotlinJvm = "org.jetbrains.kotlin.jvm"
74
const val KotlinAndroid = "org.jetbrains.kotlin.android"
85

96
const val KotlinxSerialization = "org.jetbrains.kotlin.plugin.serialization"
107

118
const val AndroidApplication = "com.android.application"
129
const val AndroidLibrary = "com.android.library"
1310

11+
const val AndroidxRoom = "androidx.room"
12+
1413
const val hilt = "dagger.hilt.android.plugin"
1514
const val Ksp = "com.google.devtools.ksp"
1615

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ plugins {
99
alias(libs.plugins.kotlin.serialization) apply false
1010
alias(libs.plugins.android.application) apply false
1111
alias(libs.plugins.android.library) apply false
12+
alias(libs.plugins.androidx.room) apply false
1213
alias(libs.plugins.hilt) apply false
1314
alias(libs.plugins.google.service) apply false
1415
alias(libs.plugins.firebase.crashlytics) apply false

core/data/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dependencies {
1515
implementations(
1616
projects.core.network,
1717
projects.core.datastore,
18+
projects.core.database,
1819

1920
libs.timber,
2021
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.unifest.android.core.data.di
2+
3+
import com.unifest.android.core.data.repository.DefaultLikedBoothRepository
4+
import com.unifest.android.core.data.repository.LikedBoothRepository
5+
import dagger.Binds
6+
import dagger.Module
7+
import dagger.hilt.InstallIn
8+
import dagger.hilt.components.SingletonComponent
9+
import javax.inject.Singleton
10+
11+
@Module
12+
@InstallIn(SingletonComponent::class)
13+
abstract class RepositoryModule {
14+
15+
@Binds
16+
@Singleton
17+
abstract fun bindLikedBoothRepository(likedBoothRepository: DefaultLikedBoothRepository): LikedBoothRepository
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.unifest.android.core.data.mapper
2+
3+
import com.unifest.android.core.data.response.BoothDetailResponse
4+
import com.unifest.android.core.data.response.MenuResponse
5+
import com.unifest.android.core.database.entity.LikedBoothEntity
6+
import com.unifest.android.core.database.entity.MenuEntity
7+
8+
internal fun LikedBoothEntity.toResponse(): BoothDetailResponse {
9+
return BoothDetailResponse(
10+
id = id,
11+
name = name,
12+
category = category,
13+
description = description,
14+
warning = warning,
15+
location = location,
16+
latitude = latitude,
17+
longitude = longitude,
18+
menus = menus.map { it.toResponse() },
19+
)
20+
}
21+
22+
internal fun MenuEntity.toResponse(): MenuResponse {
23+
return MenuResponse(
24+
id = id,
25+
name = name,
26+
price = price,
27+
imgUrl = imgUrl,
28+
)
29+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.unifest.android.core.data.mapper
2+
3+
import com.unifest.android.core.data.response.BoothDetailResponse
4+
import com.unifest.android.core.data.response.MenuResponse
5+
import com.unifest.android.core.database.entity.LikedBoothEntity
6+
import com.unifest.android.core.database.entity.MenuEntity
7+
8+
internal fun BoothDetailResponse.toDBEntity(): LikedBoothEntity {
9+
return LikedBoothEntity(
10+
id = id,
11+
name = name,
12+
category = category,
13+
description = description,
14+
warning = warning,
15+
location = location,
16+
latitude = latitude,
17+
longitude = longitude,
18+
menus = menus.map { it.toDBEntity() },
19+
isLiked = false,
20+
)
21+
}
22+
23+
internal fun MenuResponse.toDBEntity(): MenuEntity {
24+
return MenuEntity(
25+
id = id,
26+
name = name,
27+
price = price,
28+
imgUrl = imgUrl,
29+
)
30+
}

core/data/src/main/kotlin/com/unifest/android/core/data/mapper/ResponseToEntity.kt

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.unifest.android.core.data.repository
2+
3+
import com.unifest.android.core.data.mapper.toDBEntity
4+
import com.unifest.android.core.data.mapper.toResponse
5+
import com.unifest.android.core.data.response.BoothDetailResponse
6+
import com.unifest.android.core.database.LikedBoothDao
7+
import kotlinx.coroutines.flow.Flow
8+
import kotlinx.coroutines.flow.map
9+
import javax.inject.Inject
10+
11+
class DefaultLikedBoothRepository @Inject constructor(
12+
private val likedBoothDao: LikedBoothDao,
13+
) : LikedBoothRepository {
14+
override fun getLikedBoothList(): Flow<List<BoothDetailResponse>> {
15+
return likedBoothDao.getLikedBoothList().map { likedBooths ->
16+
likedBooths.map { likedBooth ->
17+
likedBooth.toResponse()
18+
}
19+
}
20+
}
21+
22+
override suspend fun insertLikedBooth(booth: BoothDetailResponse) {
23+
likedBoothDao.insertLikedBooth(booth.toDBEntity())
24+
}
25+
26+
override suspend fun deleteLikedBooth(booth: BoothDetailResponse) {
27+
likedBoothDao.deleteLikedBooth(booth.toDBEntity())
28+
}
29+
30+
override suspend fun updateLikedBooth(booth: BoothDetailResponse) {
31+
likedBoothDao.updateLikedBooth(booth.id, booth.isLiked)
32+
}
33+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.unifest.android.core.data.repository
2+
3+
import com.unifest.android.core.data.response.BoothDetailResponse
4+
import kotlinx.coroutines.flow.Flow
5+
6+
interface LikedBoothRepository {
7+
fun getLikedBoothList(): Flow<List<BoothDetailResponse>>
8+
suspend fun insertLikedBooth(booth: BoothDetailResponse)
9+
suspend fun deleteLikedBooth(booth: BoothDetailResponse)
10+
suspend fun updateLikedBooth(booth: BoothDetailResponse)
11+
}

core/data/src/main/kotlin/com/unifest/android/core/data/response/BoothDetailResponse.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ data class BoothDetailResponse(
2323
val longitude: Float,
2424
@SerialName("menus")
2525
val menus: List<MenuResponse>,
26+
val isLiked: Boolean = false,
2627
)
2728

2829
@Serializable
File renamed without changes.

core/database/build.gradle.kts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@file:Suppress("INLINE_FROM_HIGHER_PLATFORM")
2+
3+
plugins {
4+
alias(libs.plugins.unifest.android.library)
5+
alias(libs.plugins.unifest.android.hilt)
6+
alias(libs.plugins.unifest.android.room)
7+
id("kotlinx-serialization")
8+
}
9+
10+
android {
11+
namespace = "com.unifest.android.core.database"
12+
}
13+
14+
dependencies {
15+
implementations(
16+
libs.timber,
17+
)
18+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.unifest.android.core.database
2+
3+
import androidx.room.Dao
4+
import androidx.room.Delete
5+
import androidx.room.Insert
6+
import androidx.room.OnConflictStrategy
7+
import androidx.room.Query
8+
import com.unifest.android.core.database.entity.LikedBoothEntity
9+
import kotlinx.coroutines.flow.Flow
10+
11+
@Dao
12+
interface LikedBoothDao {
13+
@Insert(onConflict = OnConflictStrategy.REPLACE)
14+
suspend fun insertLikedBooth(userInfo: LikedBoothEntity)
15+
16+
@Delete
17+
suspend fun deleteLikedBooth(userInfo: LikedBoothEntity)
18+
19+
@Query("SELECT * FROM liked_booth")
20+
fun getLikedBoothList(): Flow<List<LikedBoothEntity>>
21+
22+
@Query("UPDATE liked_booth SET is_liked = :isLiked WHERE id = :id")
23+
suspend fun updateLikedBooth(id: Long, isLiked: Boolean)
24+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.unifest.android.core.database
2+
3+
import androidx.room.Database
4+
import androidx.room.RoomDatabase
5+
import androidx.room.TypeConverters
6+
import com.unifest.android.core.database.entity.LikedBoothEntity
7+
8+
@Database(
9+
entities = [LikedBoothEntity::class],
10+
version = 1,
11+
exportSchema = true,
12+
)
13+
@TypeConverters(MenuListConverter::class)
14+
abstract class LikedBoothDatabase : RoomDatabase() {
15+
abstract fun likedBoothDao(): LikedBoothDao
16+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.unifest.android.core.database
2+
3+
import androidx.room.TypeConverter
4+
import com.unifest.android.core.database.entity.MenuEntity
5+
import kotlinx.serialization.encodeToString
6+
import kotlinx.serialization.json.Json
7+
8+
class MenuListConverter {
9+
private val json = Json
10+
11+
@TypeConverter
12+
fun fromMenuList(menuList: List<MenuEntity>): String {
13+
return json.encodeToString(menuList)
14+
}
15+
16+
@TypeConverter
17+
fun toMenuList(menuListString: String): List<MenuEntity> {
18+
return json.decodeFromString(menuListString)
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.unifest.android.core.database.di
2+
3+
import com.unifest.android.core.database.LikedBoothDao
4+
import com.unifest.android.core.database.LikedBoothDatabase
5+
import dagger.Module
6+
import dagger.Provides
7+
import dagger.hilt.InstallIn
8+
import dagger.hilt.components.SingletonComponent
9+
10+
@Module
11+
@InstallIn(SingletonComponent::class)
12+
object DaoModule {
13+
@Provides
14+
fun provideLikedBoothDao(
15+
database: LikedBoothDatabase,
16+
): LikedBoothDao = database.likedBoothDao()
17+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.unifest.android.core.database.di
2+
3+
import android.content.Context
4+
import androidx.room.Room
5+
import com.unifest.android.core.database.LikedBoothDatabase
6+
import dagger.Module
7+
import dagger.Provides
8+
import dagger.hilt.InstallIn
9+
import dagger.hilt.android.qualifiers.ApplicationContext
10+
import dagger.hilt.components.SingletonComponent
11+
import javax.inject.Singleton
12+
13+
@Module
14+
@InstallIn(SingletonComponent::class)
15+
object DatabaseModule {
16+
17+
@Singleton
18+
@Provides
19+
fun provideLikedBoothDatabase(@ApplicationContext context: Context): LikedBoothDatabase =
20+
Room.databaseBuilder(
21+
context.applicationContext,
22+
LikedBoothDatabase::class.java,
23+
"liked_booth_database",
24+
).build()
25+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.unifest.android.core.database.entity
2+
3+
import androidx.room.ColumnInfo
4+
import androidx.room.Entity
5+
import androidx.room.PrimaryKey
6+
import kotlinx.serialization.Serializable
7+
8+
@Serializable
9+
@Entity(tableName = "liked_booth")
10+
data class LikedBoothEntity(
11+
@PrimaryKey
12+
@ColumnInfo(name = "id")
13+
val id: Long,
14+
@ColumnInfo(name = "name")
15+
val name: String,
16+
@ColumnInfo(name = "category")
17+
val category: String,
18+
@ColumnInfo(name = "description")
19+
val description: String,
20+
@ColumnInfo(name = "warning")
21+
val warning: String,
22+
@ColumnInfo(name = "location")
23+
val location: String,
24+
@ColumnInfo(name = "latitude")
25+
val latitude: Float,
26+
@ColumnInfo(name = "longitude")
27+
val longitude: Float,
28+
@ColumnInfo(name = "menus")
29+
val menus: List<MenuEntity>,
30+
@ColumnInfo(name = "is_liked")
31+
val isLiked: Boolean,
32+
)
33+
34+
@Serializable
35+
data class MenuEntity(
36+
val id: Long = 0L,
37+
val name: String = "",
38+
val price: Int = 0,
39+
val imgUrl: String = "",
40+
)

0 commit comments

Comments
 (0)