-
Notifications
You must be signed in to change notification settings - Fork 612
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(core): migrate from dbflow to room for client #2300
base: kmp-impl
Are you sure you want to change the base?
Conversation
@@ -17,6 +17,6 @@ import kotlinx.parcelize.Parcelize | |||
*/ | |||
@Parcelize | |||
class IdentifierTemplate( | |||
var allowedDocumentTypes: List<DocumentType>? = ArrayList(), | |||
val allowedDocumentTypes: List<DocumentType>? = ArrayList(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use emptyList() (or mutableListOf() if mutability is necessary) in instead of ArrayList(). It is more efficient to use emptyList() since it prevents needless object construction and offers superior immutability by default. For improved efficiency and clarity, use emptySet(), emptyMap(), listOf(), setOf(), and mapOf() when appropriate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do as suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggested changes implemented
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use emptyList() (or mutableListOf() if mutability is necessary) in instead of ArrayList(). It is more efficient to use emptyList() since it prevents needless object construction and offers superior immutability by default. For improved efficiency and clarity, use emptySet(), emptyMap(), listOf(), setOf(), and mapOf() when appropriate.
@HekmatullahAmin Can you cite some resources that support these statements?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @biplab1, I didn't notice your questions earlier.
Regarding sources, there are plenty of resources you can read about this, including the official Kotlin documentation. Using emptyList() is better than ArrayList() because it provides immutability by default, which prevents accidental modifications to the list.
For example:
class IdentifierTemplate(
val allowedDocumentTypes: List<DocumentType>? = ArrayList() // Mutable list
)
In this case, even though allowedDocumentTypes is declared as val (immutable reference), the list itself is mutable because ArrayList() is used. This means the contents of the list can still be modified:
val template = IdentifierTemplate()
template.allowedDocumentTypes?.add(DocumentType()) // This works, but mutability might not be intended
To prevent accidental modifications, you can use emptyList() instead:
class IdentifierTemplate(
val allowedDocumentTypes: List<DocumentType>? = emptyList() // Immutable list
)
Now, the list cannot be modified:
val template = IdentifierTemplate()
// template.allowedDocumentTypes?.add(DocumentType()) // This would cause a compile-time error
By using emptyList(), you ensure that the list cannot be changed accidentally, making your code safer and more predictable. If mutability is needed, you can use mutableListOf() instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's few things to change, these changes are not nessacary as per your task, but as you modifying repository classes this changes should required
-
Non-suspend functions returning
Flow
:
If a function returns aFlow
, it should not be marked assuspend
becauseFlow
is already designed to handle asynchronous streams.fun getItems(): Flow<List<Item>> { // Return a Flow of List<Item> }
-
Convert
List<T>
toFlow<List<T>>
:
If a function currently returns aList<T>
, it should be modified to return aFlow<List<T>>
to align with reactive programming practices.fun getItems(): Flow<List<Item>> { // Convert List<Item> to Flow<List<Item>> }
-
Suspend functions for actions (create/update/delete):
If a function performs an action like creating, updating, or deleting, it should be marked assuspend
and return aResult
orUnit
.suspend fun createItem(item: Item): Result<Unit> { // Perform create action and return Result } suspend fun updateItem(item: Item): Result<Unit> { // Perform update action and return Result } suspend fun deleteItem(itemId: String): Result<Unit> { // Perform delete action and return Result }
@niyajali Thanks for reviewing! I will do as suggested. |
de52712
to
1fedc46
Compare
fun readAllClients(): Flow<Page<Client>> | ||
|
||
@Query("SELECT * FROM GroupTable WHERE id = :groupId") | ||
fun getGroupAssociateClients(groupId: Int): Flow<GroupWithAssociations> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove Flow from here. Don't use Flow in dao unless we are retrieving list. Check the entire DAO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@biplab1 my apologies. Ignore the previous comment.
Check if we need a single item. If yes add 'LIMIT 1`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In DatabaseHelperClient.kt, this function was returning Observable<GroupWithAssociations>
, so it was changed to Flow<GroupWithAssociations>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@biplab1 This is the function right?
it should be this instead
@Query("SELECT * FROM Client WHERE groupId = :groupId")
fun getGroupAssociateClients(groupId: Int): Flow<List<Client>>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original function returned GroupWithAssociations, the one you suggest returns List<Client>
. GroupWithAssociations has a List<Client>
in it but also some other things.
fun getClient(clientId: Int): Flow<Client> | ||
|
||
@Insert(onConflict = OnConflictStrategy.REPLACE) | ||
fun saveClientAccounts( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Save, delete and update should be a suspend function always
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does your statement hold true even when the function returns a flow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes,
save, delete and update should not return flow because they are one time operations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggested changes implemented.
|
||
var additionalProperties: Map<String, Any> = HashMap(), | ||
val additionalProperties: Map<String, Any> = HashMap(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emptyMap() would be better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggested changes implemented.
@@ -186,7 +186,7 @@ class DataManagerClient @Inject constructor( | |||
* @param clientId Client ID | |||
* @return ResponseBody is the Retrofit 2 response | |||
*/ | |||
fun deleteClientImage(clientId: Int): Observable<ResponseBody> { | |||
fun deleteClientImage(clientId: Int): Flow<ResponseBody> { | |||
return mBaseApiManager.clientsApi.deleteClientImage(clientId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mBaseApiManager is used for the api call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand your statement, could you please provide more details?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for the api call. But we are migrating the database only right?
But if you want to migrate it, we need to change it to something like that.
@DELETE(APIEndPoint.CLIENTS + "/{clientId}/images")
suspend fun deleteClientImage(@Path("clientId") clientId: Int): ResponseBody
fun deleteClientImage(clientId: Int): Flow<ResponseBody> {
return flow { emit( mBaseApiManager.clientsApi.deleteClientImage(clientId) )}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was following this PR #2292, where DataManagerLoan.kt has been migrated.
@itsPronay Thanks for reviewing! I will look into your suggestions. |
@niyajali Can you cite some resources that support these statements? |
…nt-dbflow-to-room # Conflicts: # core/data/src/main/java/com/mifos/core/data/repository/ClientIdentifiersRepository.kt # core/data/src/main/java/com/mifos/core/data/repository/CreateNewClientRepository.kt # core/data/src/main/java/com/mifos/core/data/repositoryImp/ClientIdentifiersRepositoryImp.kt # core/data/src/main/java/com/mifos/core/data/repositoryImp/CreateNewClientRepositoryImp.kt # core/database/src/main/java/com/mifos/room/dao/ClientDao.kt # core/database/src/main/java/com/mifos/room/db/MifosDatabase.kt # core/database/src/main/java/com/mifos/room/di/DaoModule.kt # core/database/src/main/java/com/mifos/room/entities/client/Savings.kt
* [database.group] dbflow to room * fix checks
* MIFOSAC-342 [database.center] dbFlow to room migration
* feat(office): migrated Dbflow to Room * fix: data type and removed Gson * fix: model usage in useCase * refactor: replaced entity instead of model * fix: spotless error * fix checks failure --------- Co-authored-by: Nagarjuna <[email protected]>
* MIFOSAC-392 [database/charge] dbflow to room * backup * Fix exception * added singleton
# Conflicts: # core/data/src/main/java/com/mifos/core/data/pagingSource/ClientChargesPagingSource.kt # core/data/src/main/java/com/mifos/core/data/repository/CreateNewClientRepository.kt # core/data/src/main/java/com/mifos/core/data/repositoryImp/CreateNewClientRepositoryImp.kt # core/database/src/main/java/com/mifos/room/db/MifosDatabase.kt # core/database/src/main/java/com/mifos/room/entities/accounts/savings/SavingsAccount.kt
…droid-client into client-dbflow-to-room
173be66
to
f3bb40a
Compare
Fixes - Jira-#341
Didn't create a Jira ticket, click here to create new.
Please Add Screenshots If there are any UI changes.
Please make sure these boxes are checked before submitting your pull request - thanks!
Run the static analysis check
./gradlew check
orci-prepush.sh
to make sure you didn't break anythingIf you have multiple commits please combine them into one commit by squashing them.