Skip to content

Commit ba740e3

Browse files
add Paged useCase to fetch data
1 parent 939dfb8 commit ba740e3

6 files changed

Lines changed: 126 additions & 39 deletions

File tree

libraries/data/src/main/java/com/smarttoolfactory/data/repository/Repository.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,19 @@ interface PropertyRepositoryRxJava3 {
4444
fun getSortOrderKey(): Single<String>
4545
}
4646

47+
// TODO This can be single interface with generic input and output types
4748
interface PagedPropertyRepository {
4849

4950
fun getCurrentPageNumber(): Int
5051

5152
suspend fun fetchEntitiesFromRemoteByPage(
52-
page: Int,
5353
orderBy: String = ORDER_BY_NONE
5454
): List<PagedPropertyEntity>
5555

56+
suspend fun getPropertyCount(): Int
57+
58+
fun resetPageCount()
59+
5660
suspend fun getPropertyEntitiesFromLocal(): List<PagedPropertyEntity>
5761

5862
suspend fun savePropertyEntities(propertyEntities: List<PagedPropertyEntity>)

libraries/data/src/main/java/com/smarttoolfactory/data/repository/RepositoryImpl.kt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,31 @@ class PagedPropertyRepositoryImpl @Inject constructor(
8787
private val mapper: PropertyDTOtoPagedEntityListMapper
8888
) : PagedPropertyRepository {
8989

90-
private var currentPageNumber = 0
90+
private var currentPageNumber = 1
9191

9292
override fun getCurrentPageNumber(): Int {
9393
return currentPageNumber
9494
}
9595

9696
override suspend fun fetchEntitiesFromRemoteByPage(
97-
page: Int,
9897
orderBy: String
9998
): List<PagedPropertyEntity> {
100-
currentPageNumber = page
99+
101100
saveSortOrderKey(orderBy)
102-
return mapper.map(remoteDataSource.getPropertyDTOsWithPagination(page, orderBy))
101+
return mapper.map(
102+
remoteDataSource.getPropertyDTOsWithPagination(
103+
currentPageNumber++,
104+
orderBy
105+
)
106+
)
107+
}
108+
109+
override suspend fun getPropertyCount(): Int {
110+
return localDataSource.getPropertyCount()
111+
}
112+
113+
override fun resetPageCount() {
114+
currentPageNumber = 1
103115
}
104116

105117
override suspend fun getPropertyEntitiesFromLocal(): List<PagedPropertyEntity> {

libraries/data/src/main/java/com/smarttoolfactory/data/source/PropertyDataSource.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ interface LocalPropertyDataSourceCoroutines : PropertyDataSource {
2828
suspend fun getOrderKey(): String
2929
}
3030

31+
/*
32+
Pagination + Coroutines
33+
*/
3134
interface LocalPagedPropertyDataSource : PropertyDataSource {
3235
suspend fun getPropertyEntities(): List<PagedPropertyEntity>
3336
suspend fun saveEntities(properties: List<PagedPropertyEntity>): List<Long>
3437
suspend fun deletePropertyEntities()
38+
suspend fun getPropertyCount(): Int
3539
suspend fun saveOrderKey(orderBy: String)
3640
suspend fun getOrderKey(): String
3741
}

libraries/data/src/main/java/com/smarttoolfactory/data/source/PropertyDataSourceImpl.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ class LocalPagedPropertySourceImpl @Inject constructor(
125125
return dao.deleteAll()
126126
}
127127

128+
override suspend fun getPropertyCount(): Int {
129+
return dao.getPropertyCount()
130+
}
131+
128132
override suspend fun saveOrderKey(orderBy: String) {
129133
sortDao.insert(SortOrderEntity(orderBy = orderBy))
130134
}

libraries/domain/src/main/java/com/smarttoolfactory/domain/mapper/Mappers.kt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.smarttoolfactory.data.mapper.ListMapper
44
import com.smarttoolfactory.data.mapper.Mapper
55
import com.smarttoolfactory.data.mapper.MapperFactory
66
import com.smarttoolfactory.data.model.local.BrokerEntity
7+
import com.smarttoolfactory.data.model.local.PagedPropertyEntity
78
import com.smarttoolfactory.data.model.local.PropertyEntity
89
import com.smarttoolfactory.domain.model.BrokerItem
910
import com.smarttoolfactory.domain.model.PropertyItem
@@ -96,3 +97,68 @@ class PropertyEntityToItemListMapper @Inject constructor() :
9697
}
9798
}
9899
}
100+
101+
class PagedEntityToItemListMapper @Inject constructor() :
102+
ListMapper<PagedPropertyEntity, PropertyItem> {
103+
104+
override fun map(input: List<PagedPropertyEntity>): List<PropertyItem> {
105+
106+
return input.map { input ->
107+
108+
PropertyItem(
109+
id = input.id,
110+
update = input.update,
111+
categoryId = input.categoryId,
112+
title = input.title,
113+
subject = input.subject,
114+
type = input.type,
115+
typeId = input.typeId,
116+
thumbnail = input.thumbnail,
117+
thumbnailBig = input.thumbnailBig,
118+
imageCount = input.imageCount,
119+
price = input.price,
120+
pricePeriod = input.pricePeriod,
121+
pricePeriodRaw = input.pricePeriodRaw,
122+
priceLabel = input.priceLabel,
123+
priceValue = input.priceValue,
124+
priceValueRaw = input.priceValueRaw,
125+
currency = input.currency,
126+
featured = input.featured,
127+
location = input.location,
128+
area = input.area,
129+
poa = input.poa,
130+
reraPermit = input.reraPermit,
131+
bathrooms = input.bathrooms,
132+
bedrooms = input.bedrooms,
133+
dateInsert = input.dateInsert,
134+
dateUpdate = input.dateUpdate,
135+
agentName = input.agentName,
136+
brokerName = input.brokerName,
137+
agentLicense = input.agentLicense,
138+
locationId = input.locationId,
139+
hideLocation = input.hideLocation,
140+
141+
// Maps BrokerEntity
142+
broker =
143+
MapperFactory.createMapper<BrokerEntityToItemMapper>().map(input.broker),
144+
// Maps List<String>
145+
amenities = input.amenities,
146+
amenitiesKeys = input.amenitiesKeys,
147+
148+
latitude = input.latitude,
149+
longitude = input.longitude,
150+
premium = input.premium,
151+
livingrooms = input.livingrooms,
152+
verified = input.verified,
153+
154+
// Maps List<String>
155+
gallery = input.gallery,
156+
phone = input.phone,
157+
158+
// Maps List<String>
159+
leadEmailReceivers = input.leadEmailReceivers,
160+
reference = input.reference,
161+
)
162+
}
163+
}
164+
}

libraries/domain/src/main/java/com/smarttoolfactory/domain/usecase/GetPropertiesUseCasePaged.kt

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,52 @@
11
package com.smarttoolfactory.domain.usecase
22

33
import com.smarttoolfactory.data.constant.ORDER_BY_NONE
4-
import com.smarttoolfactory.data.model.local.PropertyEntity
5-
import com.smarttoolfactory.data.repository.PropertyRepositoryCoroutines
4+
import com.smarttoolfactory.data.model.local.PagedPropertyEntity
5+
import com.smarttoolfactory.data.repository.PagedPropertyRepository
66
import com.smarttoolfactory.domain.dispatcher.UseCaseDispatchers
77
import com.smarttoolfactory.domain.error.EmptyDataException
8-
import com.smarttoolfactory.domain.mapper.PropertyEntityToItemListMapper
8+
import com.smarttoolfactory.domain.mapper.PagedEntityToItemListMapper
99
import com.smarttoolfactory.domain.model.PropertyItem
1010
import javax.inject.Inject
1111
import kotlinx.coroutines.flow.Flow
1212
import kotlinx.coroutines.flow.catch
1313
import kotlinx.coroutines.flow.emitAll
14+
import kotlinx.coroutines.flow.flatMapConcat
1415
import kotlinx.coroutines.flow.flow
1516
import kotlinx.coroutines.flow.flowOf
1617
import kotlinx.coroutines.flow.flowOn
1718
import kotlinx.coroutines.flow.map
1819

19-
/**
20-
* UseCase for getting UI Item list with offline first or offline last approach.
21-
*
22-
* * *Offline-first* first source to look for data is local data source, or database,
23-
* if database is empty or if caching is used it's expiry date is over, looks for remote source
24-
* for data. If both of the sources are empty, either return empty list or error to notify UI.
25-
*
26-
* This approach is good for when user is offline or have no internet connection, additional logic
27-
* can be added to check if user is offline to not deleted cached data.
28-
*
29-
* * *Offline-last* always checks remote data source for data and applies to database or offline
30-
* source as last resort. Offline-last is used especially when user refreshes data with a UI
31-
* element to get the latest data or new data is always first preference.
32-
*/
3320
class GetPropertiesUseCasePaged @Inject constructor(
34-
private val repository: PropertyRepositoryCoroutines,
35-
private val mapper: PropertyEntityToItemListMapper,
21+
private val repository: PagedPropertyRepository,
22+
private val mapper: PagedEntityToItemListMapper,
3623
private val dispatcherProvider: UseCaseDispatchers
3724
) {
3825

3926
/**
40-
* Function to retrieve data from repository with offline-last which checks
41-
* REMOTE data source first.
42-
*
43-
* * Check out Remote Source first
44-
* * If empty data or null returned throw empty set exception
45-
* * If error occurred while fetching data from remote: Try to fetch data from db
46-
* * If data is fetched from remote source: delete old data, save new data and return new data
47-
* * If both network and db don't have any data throw empty set exception
27+
* Fetches data from REMOTE source with PAGINATION
28+
* using specified parameter parameter. Page number i s kept in [PagedPropertyRepository].
4829
*
30+
* * Since [PagedPropertyEntity] insert order is not kept
31+
* it's required to add an index for insertion or to db to get valid data which is ordered
32+
* in server side
4933
*/
50-
fun getPagedOfflineLast(page: Int, orderBy: String): Flow<List<PropertyItem>> {
51-
return flow { emit(repository.fetchEntitiesFromRemote(orderBy)) }
34+
fun getPagedOfflineLast(orderBy: String): Flow<List<PropertyItem>> {
35+
36+
return flow { emit(repository.fetchEntitiesFromRemoteByPage(orderBy)) }
5237
.map {
5338
if (it.isNullOrEmpty()) {
5439
throw EmptyDataException("No Data is available in Remote source!")
5540
} else {
5641
repository.run {
5742

58-
if (page == 1) {
59-
deletePropertyEntities()
60-
}
43+
deletePropertyEntities()
44+
45+
val propertyCount = repository.getPropertyCount()
6146

6247
// 🔥 Add an insert order since we are not using Room's ORDER BY
6348
it.forEachIndexed { index, propertyEntity ->
64-
propertyEntity.insertOrder = index
49+
propertyEntity.insertOrder = propertyCount + index
6550
}
6651
savePropertyEntities(it)
6752

@@ -79,7 +64,19 @@ class GetPropertiesUseCasePaged @Inject constructor(
7964
}
8065
}
8166

82-
private fun toPropertyListOrError(entityList: List<PropertyEntity>): List<PropertyItem> {
67+
/**
68+
* Resets page number to 1, clears previous data from database and fetches new data
69+
* from REMOTE source with given param
70+
*/
71+
fun refreshData(orderBy: String): Flow<List<PropertyItem>> {
72+
return flow { emit(repository.resetPageCount()) }
73+
.flatMapConcat {
74+
repository.deletePropertyEntities()
75+
getPagedOfflineLast(orderBy)
76+
}
77+
}
78+
79+
private fun toPropertyListOrError(entityList: List<PagedPropertyEntity>): List<PropertyItem> {
8380
return if (!entityList.isNullOrEmpty()) {
8481
mapper.map(entityList)
8582
} else {

0 commit comments

Comments
 (0)