Skip to content

Commit

Permalink
Merge pull request #2 from f-lab-edu/feature/1
Browse files Browse the repository at this point in the history
[#1] 지출내역 Database 구현
  • Loading branch information
ksw4015 authored Nov 28, 2024
2 parents 750a616 + 57b95df commit c026e20
Show file tree
Hide file tree
Showing 10 changed files with 413 additions and 28 deletions.
15 changes: 11 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.ksp)
}

android {
Expand All @@ -18,6 +19,9 @@ android {
vectorDrawables {
useSupportLibrary = true
}
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}
}

buildTypes {
Expand All @@ -30,11 +34,11 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_19
targetCompatibility = JavaVersion.VERSION_19
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "19"
jvmTarget = "17"
}
buildFeatures {
compose = true
Expand All @@ -50,7 +54,6 @@ android {
}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
Expand All @@ -59,6 +62,10 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)

implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
Expand Down

This file was deleted.

173 changes: 173 additions & 0 deletions app/src/androidTest/java/kr/ksw/mybudget/data/local/SpendingDaoTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package kr.ksw.mybudget.data.local

import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import kr.ksw.mybudget.R
import kr.ksw.mybudget.data.local.dao.SpendingDao
import kr.ksw.mybudget.data.local.databases.MyBudgetDatabase
import kr.ksw.mybudget.data.local.entity.SpendingEntity
import kr.ksw.mybudget.data.local.mock.MAJOR_CATEGORY_FOOD
import kr.ksw.mybudget.data.local.mock.MAJOR_CATEGORY_LIFE_STYLE
import kr.ksw.mybudget.data.local.mock.spendingList
import kr.ksw.mybudget.data.local.mock.spendingListForBetween
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.IOException
import java.time.LocalDate

@RunWith(AndroidJUnit4::class)
class SpendingDaoTest {
private lateinit var db: MyBudgetDatabase
private lateinit var dao: SpendingDao

@Before
fun createDB() {
val context = ApplicationProvider.getApplicationContext<Context>()
db = Room.inMemoryDatabaseBuilder(
context,
MyBudgetDatabase::class.java
).build()
dao = db.spendingDao
}

@After
@Throws(IOException::class)
fun closeDB() {
db.close()
}

@Test
fun getAllSpendingEntitiesIsEmpty() = runTest {
val result = dao.getAllSpendingEntities().first()
assert(result.isEmpty())
}

@Test
fun upsertSpendingEntity() = runTest {
val context = ApplicationProvider.getApplicationContext<Context>()
dao.upsertSpendingEntity(SpendingEntity(
title = "스타벅스",
date = LocalDate.now(),
majorCategory = context.resources.getInteger(R.integer.category_food),
subCategory = context.resources.getInteger(R.integer.category_cafe),
price = 5_000
))
val result = dao.getAllSpendingEntities().first()
assert(result.isNotEmpty())
}

@Test
fun deleteSpendingEntity() = runTest {
val context = ApplicationProvider.getApplicationContext<Context>()
val spending = SpendingEntity(
id = 1,
title = "스타벅스",
date = LocalDate.now(),
majorCategory = context.resources.getInteger(R.integer.category_food),
subCategory = context.resources.getInteger(R.integer.category_cafe),
price = 5_000
)
dao.upsertSpendingEntity(spending)
assert(dao.getAllSpendingEntities().first().isNotEmpty())
dao.deleteSpendingEntity(spending)
assert(dao.getAllSpendingEntities().first().isEmpty())
}

@Test
fun `getSpendingEntitiesByMajorCategory Test Food Result Count is 2`() = runTest {
spendingList.forEach { spending ->
dao.upsertSpendingEntity(spending)
}
assert(dao.getAllSpendingEntities().first().isNotEmpty())

val result = dao.getSpendingEntitiesByMajorCategory(MAJOR_CATEGORY_FOOD)
assert(result.isNotEmpty())
assert(result.size == 2)
}

@Test
fun `getSpendingEntitiesBySubCategory Test LifeStyle And Transportation Category`() = runTest {
spendingList.forEach { spending ->
dao.upsertSpendingEntity(spending)
}
assert(dao.getAllSpendingEntities().first().isNotEmpty())

val resultLifeStyle = dao.getSpendingEntitiesByMajorCategory(MAJOR_CATEGORY_LIFE_STYLE)
assert(resultLifeStyle.size == 2)

val categoryTransportation = 31
val resultTransportation = dao.getSpendingEntitiesBySubCategory(categoryTransportation)
assert(resultTransportation.size == 1)
}

@Test
fun `getSpendingEntitiesBetween Today`() = runTest {
spendingList.forEach { spending ->
dao.upsertSpendingEntity(spending)
}
val from = LocalDate.now()
val to = LocalDate.now()
val result = dao.getSpendingEntitiesBetween(from, to)
assert(result.isNotEmpty())
assert(result.size == spendingList.size)
}

@Test
fun `getSpendingEntitiesBetween Week`() = runTest {
val now = LocalDate.now()
val from = now.plusDays(-((now.dayOfWeek.value - 1).toLong()))
val to = now.plusDays((7 - now.dayOfWeek.value).toLong())
spendingListForBetween.forEach { spending ->
dao.upsertSpendingEntity(spending)
}
val result = dao.getSpendingEntitiesBetween(from, to)
assert(result.isNotEmpty())
assert(result.size == 1)
}

@Test
fun `getSpendingEntitiesBetween Month`() = runTest {
val now = LocalDate.now()
val from = now.withDayOfMonth(1)
val to = now.withDayOfMonth(now.lengthOfMonth())
spendingListForBetween.forEach { spending ->
dao.upsertSpendingEntity(spending)
}
val result = dao.getSpendingEntitiesBetween(from, to)
assert(result.isNotEmpty())
assert(result.size == 2)
}

@Test
fun `getSpendingEntitiesBetween One Month Before`() = runTest {
val month = LocalDate.now().plusMonths(-1L)
val from = month.withDayOfMonth(1)
val to = month.withDayOfMonth(month.lengthOfMonth())
println("$from, $to")
spendingListForBetween.forEach { spending ->
dao.upsertSpendingEntity(spending)
}
val result = dao.getSpendingEntitiesBetween(from, to)
assert(result.isNotEmpty())
assert(result.size == 1)
}

@Test
fun `getSpendingEntitiesBetween Year`() = runTest {
val now = LocalDate.now()
val from = now.withDayOfYear(1)
println("$from, $now")
spendingListForBetween.forEach { spending ->
dao.upsertSpendingEntity(spending)
}
val result = dao.getSpendingEntitiesBetween(from, now)
assert(result.isNotEmpty())
assert(result.size == spendingListForBetween.size)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package kr.ksw.mybudget.data.local.mock

import kr.ksw.mybudget.data.local.entity.SpendingEntity
import java.time.LocalDate

const val MAJOR_CATEGORY_FOOD = 1
const val MAJOR_CATEGORY_CULTURE = 2
const val MAJOR_CATEGORY_LIFE_STYLE = 3
const val MAJOR_CATEGORY_CASH = 4

val spendingList = listOf(
SpendingEntity(
title = "스타벅스",
date = LocalDate.now(),
majorCategory = MAJOR_CATEGORY_FOOD,
subCategory = 12,
price = 6_000
),
SpendingEntity(
title = "할리스",
date = LocalDate.now(),
majorCategory = MAJOR_CATEGORY_FOOD,
subCategory = 12,
price = 5_000
),
SpendingEntity(
title = "영화",
date = LocalDate.now(),
majorCategory = MAJOR_CATEGORY_CULTURE,
subCategory = 22,
price = 15_000
),
SpendingEntity(
title = "교통비",
date = LocalDate.now(),
majorCategory = MAJOR_CATEGORY_LIFE_STYLE,
subCategory = 31,
price = 100_000
),
SpendingEntity(
title = "통신비",
date = LocalDate.now(),
majorCategory = MAJOR_CATEGORY_LIFE_STYLE,
subCategory = 32,
price = 50_000
),
SpendingEntity(
title = "송금",
date = LocalDate.now(),
majorCategory = MAJOR_CATEGORY_CASH,
subCategory = 41,
price = 200_000
),
)

val spendingListForBetween = listOf(
SpendingEntity(
title = "송금",
date = LocalDate.now().plusWeeks(-1L),
majorCategory = MAJOR_CATEGORY_CASH,
subCategory = 41,
price = 200_000
),
SpendingEntity(
title = "송금",
date = LocalDate.now().plusMonths(-1L),
majorCategory = MAJOR_CATEGORY_CASH,
subCategory = 41,
price = 200_000
),
SpendingEntity(
title = "송금",
date = LocalDate.now(),
majorCategory = MAJOR_CATEGORY_CASH,
subCategory = 41,
price = 200_000
),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package kr.ksw.mybudget.data.local.converter

import androidx.room.TypeConverter
import java.time.LocalDate

class Converters {
@TypeConverter
fun fromTimestamp(value: Int?): LocalDate? {
return value?.let { LocalDate.ofYearDay(LocalDate.now().year, value) }
}

@TypeConverter
fun dateToTimestamp(date: LocalDate?): Int? {
return date?.dayOfYear
}
}
38 changes: 38 additions & 0 deletions app/src/main/java/kr/ksw/mybudget/data/local/dao/SpendingDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package kr.ksw.mybudget.data.local.dao

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Query
import androidx.room.Upsert
import kotlinx.coroutines.flow.Flow
import kr.ksw.mybudget.data.local.entity.SpendingEntity
import java.time.LocalDate
import java.util.Date

@Dao
interface SpendingDao {
@Upsert
suspend fun upsertSpendingEntity(spendingEntity: SpendingEntity)

@Delete
suspend fun deleteSpendingEntity(spendingEntity: SpendingEntity)

@Query("SELECT * FROM spending_table")
fun getAllSpendingEntities(): Flow<List<SpendingEntity>>

@Query("SELECT * FROM spending_table WHERE majorCategory = :majorCategory")
suspend fun getSpendingEntitiesByMajorCategory(
majorCategory: Int
): List<SpendingEntity>

@Query("SELECT * FROM spending_table WHERE subCategory = :subCategory")
suspend fun getSpendingEntitiesBySubCategory(
subCategory: Int
): List<SpendingEntity>

@Query("SELECT * FROM spending_table WHERE date BETWEEN :from AND :to")
suspend fun getSpendingEntitiesBetween(
from: LocalDate,
to: LocalDate
): List<SpendingEntity>
}
Loading

0 comments on commit c026e20

Please sign in to comment.