Skip to content

Commit

Permalink
feat: 정책 검색 기능 완료
Browse files Browse the repository at this point in the history
  • Loading branch information
rhkrwngud445 committed Jan 1, 2025
1 parent fd13aa3 commit 6c1f3ee
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import com.withpeace.withpeace.core.database.SearchKeywordEntity
import com.withpeace.withpeace.core.domain.model.search.SearchKeyword

fun SearchKeywordEntity.toDomain(): SearchKeyword {
return SearchKeyword(keyword ?: "")
return SearchKeyword(keyword)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.withpeace.withpeace.core.data.paging

import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.skydoves.sandwich.ApiResponse
import com.withpeace.withpeace.core.data.mapper.youthpolicy.toDomain
import com.withpeace.withpeace.core.domain.model.error.CheonghaError
import com.withpeace.withpeace.core.domain.model.error.NoSearchResultException
import com.withpeace.withpeace.core.domain.model.policy.YouthPolicy
import com.withpeace.withpeace.core.domain.repository.UserRepository
import com.withpeace.withpeace.core.network.di.service.YouthPolicyService
Expand All @@ -16,8 +16,9 @@ class PolicySearchPagingSource(
private val keyword: String,
private val onError: suspend (CheonghaError) -> Unit,
private val userRepository: UserRepository,
) : PagingSource<Int, YouthPolicy>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, YouthPolicy> {
private val onReceiveTotalCount: suspend (Int) -> Unit,
) : PagingSource<Int, Pair<Int, YouthPolicy>>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Pair<Int, YouthPolicy>> {
val pageIndex = params.key ?: 1
val response = youthPolicyService.search(
keyword = keyword,
Expand All @@ -27,19 +28,26 @@ class PolicySearchPagingSource(

if (response is ApiResponse.Success) {
val successResponse = (response).data
onReceiveTotalCount(successResponse.data.totalCount)
if (response.data.data.totalCount == 0) {
return LoadResult.Error(NoSearchResultException())
}
return LoadResult.Page(
data = successResponse.data.policies.map { it.toDomain() },
data = successResponse.data.policies.map {
Pair(
successResponse.data.totalCount,
it.toDomain(),
)
},
prevKey = if (pageIndex == STARTING_PAGE_INDEX) null else pageIndex - 1,
nextKey = if (successResponse.data.policies.isEmpty()) null else pageIndex + (params.loadSize / pageSize),
)
} else {
// 방법1 Error exception 으로 구분
// 방법2 exception을 하단에서 방출
return LoadResult.Error(IllegalStateException("api state error"))
}
}

override fun getRefreshKey(state: PagingState<Int, YouthPolicy>): Int? { // 현재 포지션에서 Refresh pageKey 설정
override fun getRefreshKey(state: PagingState<Int, Pair<Int, YouthPolicy>>): Int? { // 현재 포지션에서 Refresh pageKey 설정
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.withpeace.withpeace.core.data.repository

import android.util.Log
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
Expand Down Expand Up @@ -107,7 +108,8 @@ class DefaultYouthPolicyRepository @Inject constructor(
override fun search(
searchKeyword: SearchKeyword,
onError: suspend (CheonghaError) -> Unit,
): Flow<PagingData<YouthPolicy>> {
onReceiveTotalCount: (Int) -> Unit,
): Flow<PagingData<Pair<Int, YouthPolicy>>> {
return Pager(
config = PagingConfig(PAGE_SIZE),
pagingSourceFactory = {
Expand All @@ -117,6 +119,7 @@ class DefaultYouthPolicyRepository @Inject constructor(
onError = onError,
userRepository = userRepository,
pageSize = PAGE_SIZE,
onReceiveTotalCount = onReceiveTotalCount
)
},
).flow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.withpeace.withpeace.core.database

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Entity
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
Expand All @@ -13,15 +12,12 @@ interface SearchKeywordDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertKeyword(keyword: SearchKeywordEntity)

@Query("SELECT * FROM recent_search_keywords ORDER BY timestamp DESC")
@Query("SELECT * FROM recent_search_keywords ORDER BY timestamp DESC LIMIT 8")
suspend fun getAllKeywords(): List<SearchKeywordEntity>

@Delete
suspend fun deleteKeyword(keyword: SearchKeywordEntity)

@Query("DELETE FROM recent_search_keywords WHERE id = :id")
suspend fun deleteKeywordById(id: Int)

@Query("DELETE FROM recent_search_keywords WHERE keyword = :keyword")
suspend fun deleteKeywordByValue(keyword: String)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.room.PrimaryKey

@Entity(tableName = "recent_search_keywords")
data class SearchKeywordEntity(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val keyword: String,
@PrimaryKey(autoGenerate = false) val keyword: String,
val timestamp: Long = System.currentTimeMillis(), // 저장 시각
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ sealed interface ClientError : CheonghaError {
data object NoSearchResult : SearchError
data object SingleCharacterSearch : SearchError
}
}
}

class NoSearchResultException: IllegalStateException()
class SingleCharacterSearchException: IllegalStateException()

Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ interface YouthPolicyRepository {
fun search(
searchKeyword: SearchKeyword,
onError: suspend (CheonghaError) -> Unit,
): Flow<PagingData<YouthPolicy>>
onReceiveTotalCount: (Int) -> Unit,
): Flow<PagingData<Pair<Int, YouthPolicy>>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import javax.inject.Inject
class ClearAllKeywordsUseCase @Inject constructor(
private val repository: RecentSearchKeywordRepository
) {
suspend fun invoke() {
suspend operator fun invoke() {
repository.clearAllKeywords()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.withpeace.withpeace.core.domain.usecase
import androidx.paging.PagingData
import com.withpeace.withpeace.core.domain.model.error.CheonghaError
import com.withpeace.withpeace.core.domain.model.error.ClientError
import com.withpeace.withpeace.core.domain.model.error.SingleCharacterSearchException
import com.withpeace.withpeace.core.domain.model.policy.YouthPolicy
import com.withpeace.withpeace.core.domain.model.search.SearchKeyword
import com.withpeace.withpeace.core.domain.repository.YouthPolicyRepository
Expand All @@ -16,13 +17,15 @@ class SearchUseCase @Inject constructor(
operator fun invoke(
onError: suspend (CheonghaError) -> Unit,
keyword: String,
): Flow<PagingData<YouthPolicy>> {
onReceiveTotalCount: (Int) -> Unit,
): Flow<PagingData<Pair<Int, YouthPolicy>>> {
if (SearchKeyword.validate(keyword).not()) {
return flow { onError(ClientError.SearchError.SingleCharacterSearch) }
throw SingleCharacterSearchException()
}
return youthPolicyRepository.search(
searchKeyword = SearchKeyword(keyword),
onError = onError,
onReceiveTotalCount
)
}
}
Loading

0 comments on commit 6c1f3ee

Please sign in to comment.