Skip to content

Commit 8cadf6e

Browse files
authored
[AND-257] Introduce API Model Transformer (#5568)
* Create transformers for Message and Channel * Use transformer when mapping models * Refactor mappers * Fix test compilation * Fix checkstyle * Remove `!!` from our Mappers * Create UserTransformer * Use userTransformer to transform user entity * Fix checkstyle * Use userId when possible * Add tests to test transformer in action * Fix CheckStyle * Fix * Fix ApiCheck * Fix * Update CHANGELOG.md * Fix * Move Transformers to its own package * Rename transformer parameters * Fix javadoc * Add javadoc for public methods * Fix checkstyle
1 parent 3268d8d commit 8cadf6e

File tree

78 files changed

+2898
-2169
lines changed

Some content is hidden

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

78 files changed

+2898
-2169
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
### ⬆️ Improved
2121

2222
### ✅ Added
23+
- Introduced `ApiModelTransformers` to allow custom transformations of API models. (#5568)[https://github.com/GetStream/stream-chat-android/pull/5568]
2324

2425
### ⚠️ Changed
2526

stream-chat-android-client/api/stream-chat-android-client.api

+16-2
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ public final class io/getstream/chat/android/client/ChatClient$Builder : io/gets
235235
public final fun okHttpClient (Lokhttp3/OkHttpClient;)Lio/getstream/chat/android/client/ChatClient$Builder;
236236
public final fun retryPolicy (Lio/getstream/result/call/retry/RetryPolicy;)Lio/getstream/chat/android/client/ChatClient$Builder;
237237
public final fun uploadAttachmentsNetworkType (Lio/getstream/chat/android/models/UploadAttachmentsNetworkType;)Lio/getstream/chat/android/client/ChatClient$Builder;
238+
public final fun withApiModelTransformer (Lio/getstream/chat/android/client/transformer/ApiModelTransformers;)Lio/getstream/chat/android/client/ChatClient$Builder;
238239
public final fun withPlugins ([Lio/getstream/chat/android/client/plugin/factory/PluginFactory;)Lio/getstream/chat/android/client/ChatClient$Builder;
239240
public final fun withRepositoryFactoryProvider (Lio/getstream/chat/android/client/persistance/repository/factory/RepositoryFactory$Provider;)Lio/getstream/chat/android/client/ChatClient$Builder;
240241
}
@@ -2501,12 +2502,14 @@ public final class io/getstream/chat/android/client/extensions/AttachmentExtensi
25012502

25022503
public final class io/getstream/chat/android/client/extensions/ChannelExtensionKt {
25032504
public static final fun countUnreadMentionsForUser (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;)I
2504-
public static final fun getCurrentUserUnreadCount (Lio/getstream/chat/android/models/Channel;)I
2505+
public static final fun currentUserUnreadCount (Lio/getstream/chat/android/models/Channel;Ljava/lang/String;)I
2506+
public static synthetic fun currentUserUnreadCount$default (Lio/getstream/chat/android/models/Channel;Ljava/lang/String;ILjava/lang/Object;)I
25052507
public static final fun isAnonymousChannel (Lio/getstream/chat/android/models/Channel;)Z
25062508
public static final fun isArchive (Lio/getstream/chat/android/models/Channel;)Z
25072509
public static final fun isMutedFor (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;)Z
25082510
public static final fun isPinned (Lio/getstream/chat/android/models/Channel;)Z
2509-
public static final fun syncUnreadCountWithReads (Lio/getstream/chat/android/models/Channel;)Lio/getstream/chat/android/models/Channel;
2511+
public static final fun syncUnreadCountWithReads (Lio/getstream/chat/android/models/Channel;Ljava/lang/String;)Lio/getstream/chat/android/models/Channel;
2512+
public static synthetic fun syncUnreadCountWithReads$default (Lio/getstream/chat/android/models/Channel;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/chat/android/models/Channel;
25102513
}
25112514

25122515
public final class io/getstream/chat/android/client/extensions/FlowExtensions {
@@ -3163,6 +3166,17 @@ public abstract interface class io/getstream/chat/android/client/token/TokenProv
31633166
public abstract fun loadToken ()Ljava/lang/String;
31643167
}
31653168

3169+
public final class io/getstream/chat/android/client/transformer/ApiModelTransformers {
3170+
public fun <init> ()V
3171+
public fun <init> (Lio/getstream/chat/android/models/MessageTransformer;Lio/getstream/chat/android/models/MessageTransformer;Lio/getstream/chat/android/models/ChannelTransformer;Lio/getstream/chat/android/models/UserTransformer;Lio/getstream/chat/android/models/UserTransformer;)V
3172+
public synthetic fun <init> (Lio/getstream/chat/android/models/MessageTransformer;Lio/getstream/chat/android/models/MessageTransformer;Lio/getstream/chat/android/models/ChannelTransformer;Lio/getstream/chat/android/models/UserTransformer;Lio/getstream/chat/android/models/UserTransformer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
3173+
public final fun getIncomingChannelTransformer ()Lio/getstream/chat/android/models/ChannelTransformer;
3174+
public final fun getIncomingMessageTransformer ()Lio/getstream/chat/android/models/MessageTransformer;
3175+
public final fun getIncomingUserTransformer ()Lio/getstream/chat/android/models/UserTransformer;
3176+
public final fun getOutgoingMessageTransformer ()Lio/getstream/chat/android/models/MessageTransformer;
3177+
public final fun getOutgoingUserTransformers ()Lio/getstream/chat/android/models/UserTransformer;
3178+
}
3179+
31663180
public abstract interface class io/getstream/chat/android/client/uploader/FileTransformer {
31673181
public abstract fun transform (Ljava/io/File;)Ljava/io/File;
31683182
}

stream-chat-android-client/src/debug/java/io/getstream/chat/android/client/di/ChatModule.kt

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import io.getstream.chat.android.client.parser.ChatParser
2525
import io.getstream.chat.android.client.scope.ClientScope
2626
import io.getstream.chat.android.client.scope.UserScope
2727
import io.getstream.chat.android.client.token.TokenManager
28+
import io.getstream.chat.android.client.transformer.ApiModelTransformers
2829
import io.getstream.chat.android.client.uploader.FileTransformer
2930
import io.getstream.chat.android.client.uploader.FileUploader
3031
import okhttp3.OkHttpClient
@@ -41,6 +42,7 @@ internal class ChatModule(
4142
userScope: UserScope,
4243
config: ChatClientConfig,
4344
notificationsHandler: NotificationHandler,
45+
apiModelTransformers: ApiModelTransformers,
4446
fileTransformer: FileTransformer,
4547
uploader: FileUploader?,
4648
tokenManager: TokenManager,
@@ -53,6 +55,7 @@ internal class ChatModule(
5355
userScope,
5456
config,
5557
notificationsHandler,
58+
apiModelTransformers,
5659
fileTransformer,
5760
uploader,
5861
tokenManager,

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/ChatClient.kt

+20-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ import io.getstream.chat.android.client.api.models.identifier.SendReactionIdenti
5858
import io.getstream.chat.android.client.api.models.identifier.ShuffleGiphyIdentifier
5959
import io.getstream.chat.android.client.api.models.identifier.UpdateMessageIdentifier
6060
import io.getstream.chat.android.client.api.models.identifier.getNewerRepliesIdentifier
61-
import io.getstream.chat.android.client.api2.mapping.toDto
61+
import io.getstream.chat.android.client.api2.mapping.DtoMapping
6262
import io.getstream.chat.android.client.api2.model.dto.AttachmentDto
6363
import io.getstream.chat.android.client.api2.model.dto.DownstreamChannelDto
6464
import io.getstream.chat.android.client.api2.model.dto.DownstreamMessageDto
@@ -132,6 +132,7 @@ import io.getstream.chat.android.client.token.ConstantTokenProvider
132132
import io.getstream.chat.android.client.token.TokenManager
133133
import io.getstream.chat.android.client.token.TokenManagerImpl
134134
import io.getstream.chat.android.client.token.TokenProvider
135+
import io.getstream.chat.android.client.transformer.ApiModelTransformers
135136
import io.getstream.chat.android.client.uploader.FileTransformer
136137
import io.getstream.chat.android.client.uploader.FileUploader
137138
import io.getstream.chat.android.client.uploader.NoOpFileTransformer
@@ -236,6 +237,7 @@ public class ChatClient
236237
internal constructor(
237238
public val config: ChatClientConfig,
238239
private val api: ChatApi,
240+
private val dtoMapping: DtoMapping,
239241
private val notifications: ChatNotifications,
240242
private val tokenManager: TokenManager = TokenManagerImpl(),
241243
private val userCredentialStorage: UserCredentialStorage,
@@ -2733,6 +2735,12 @@ internal constructor(
27332735
set = set,
27342736
unset = unset,
27352737
)
2738+
.flatMap { users ->
2739+
when (val user = users.firstOrNull { it.id == id }) {
2740+
null -> ErrorCall(userScope, Error.GenericError("User with id $id not found"))
2741+
else -> CoroutineCall(userScope) { Result.Success(user) }
2742+
}
2743+
}
27362744
}
27372745

27382746
/**
@@ -3199,7 +3207,7 @@ internal constructor(
31993207
params: CreateChannelParams,
32003208
): Call<Channel> {
32013209
val currentUser = getCurrentUser()
3202-
val members = params.members.map(MemberData::toDto)
3210+
val members = with(dtoMapping) { params.members.map { it.toDto() } }
32033211
val queryChannelRequest = QueryChannelRequest()
32043212
.withData(params.extraData + mapOf(QueryChannelRequest.KEY_MEMBERS to members))
32053213
return queryChannelInternal(
@@ -3591,6 +3599,7 @@ internal constructor(
35913599
private var repositoryFactoryProvider: RepositoryFactory.Provider? = null
35923600
private var uploadAttachmentsNetworkType = UploadAttachmentsNetworkType.CONNECTED
35933601
private var fileTransformer: FileTransformer = NoOpFileTransformer
3602+
private var apiModelTransformers: ApiModelTransformers = ApiModelTransformers()
35943603

35953604
/**
35963605
* Sets the log level to be used by the client.
@@ -3667,6 +3676,13 @@ internal constructor(
36673676
this.fileTransformer = fileTransformer
36683677
}
36693678

3679+
/**
3680+
* Sets a custom [ApiModelTransformers] implementation that will be used by the client to transform models.
3681+
*/
3682+
public fun withApiModelTransformer(apiModelTransformers: ApiModelTransformers): Builder = apply {
3683+
this.apiModelTransformers = apiModelTransformers
3684+
}
3685+
36703686
/**
36713687
* Sets a custom file uploader implementation that will be used by the client
36723688
* to upload files and images.
@@ -3861,6 +3877,7 @@ internal constructor(
38613877
context = appContext,
38623878
notificationConfig = notificationConfig,
38633879
),
3880+
apiModelTransformers = apiModelTransformers,
38643881
fileTransformer = fileTransformer,
38653882
uploader = fileUploader,
38663883
tokenManager = tokenManager,
@@ -3887,6 +3904,7 @@ internal constructor(
38873904
return ChatClient(
38883905
config,
38893906
module.api(),
3907+
module.dtoMapping,
38903908
module.notifications(),
38913909
tokenManager,
38923910
userCredentialStorage = userCredentialStorage ?: SharedPreferencesCredentialStorage(appContext),

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/ChatApi.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ internal interface ChatApi {
233233
id: String,
234234
set: Map<String, Any>,
235235
unset: List<String>,
236-
): Call<User>
236+
): Call<List<User>>
237237

238238
fun queryChannel(
239239
channelType: String,

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/internal/ExtraDataValidator.kt

+17-2
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ internal class ExtraDataValidator(
8383
.withExtraDataValidation(users)
8484
}
8585

86-
override fun partialUpdateUser(id: String, set: Map<String, Any>, unset: List<String>): Call<User> {
86+
override fun partialUpdateUser(id: String, set: Map<String, Any>, unset: List<String>): Call<List<User>> {
8787
return delegate.partialUpdateUser(id, set, unset)
88-
.withExtraDataValidation(set)
88+
.withExtraDataValidationOnList(set)
8989
}
9090

9191
override fun addMembers(
@@ -165,6 +165,21 @@ internal class ExtraDataValidator(
165165
}
166166
}
167167

168+
private inline fun <reified T : CustomObject> Call<List<T>>.withExtraDataValidationOnList(
169+
extraData: Map<String, Any>,
170+
): Call<List<T>> {
171+
val reserved = extraData.findReserved<T>()
172+
return when (reserved.isEmpty()) {
173+
true -> this
174+
else -> ErrorCall(
175+
scope,
176+
Error.GenericError(
177+
message = "'extraData' contains reserved keys: ${reserved.joinToString()}",
178+
),
179+
)
180+
}
181+
}
182+
168183
private fun <T : CustomObject> List<T>.findReserved(): Pair<T?, List<String>?> {
169184
for (obj in this) {
170185
val reserved = obj.findReserved()

0 commit comments

Comments
 (0)