### Generate Reverse Copy Functions with @CopyFrom Source: https://context7.com/tbsten/cream/llms.txt The `@CopyFrom` annotation generates extension functions to copy properties from a source class (e.g., an API response model) to a target class (e.g., a domain model). This simplifies data transformation, allowing for clean mapping and the ability to override specific properties during the conversion. ```kotlin import me.tbsten.cream.CopyFrom // Data layer model (from repository/network) data class UserApiResponse( val id: String, val name: String, val email: String, val createdAt: Long, ) // Domain layer model @CopyFrom(UserApiResponse::class) data class User( val id: String, val name: String, val email: String, val createdAt: Long, ) // Usage in Repository: class UserRepository(private val api: UserApi) { suspend fun getUser(userId: String): User { val response: UserApiResponse = api.fetchUser(userId) // With cream.kt - clean transformation: return response.copyToUser() } suspend fun getUserWithOverride(userId: String, customName: String): User { val response: UserApiResponse = api.fetchUser(userId) // Override specific properties while keeping others: return response.copyToUser(name = customName) } } ``` -------------------------------- ### Map Properties Between Classes with @CopyTo.Map and @CopyFrom.Map Source: https://github.com/tbsten/cream/blob/main/README.ja.md Use @CopyTo.Map and @CopyFrom.Map to specify property mappings when the source and destination classes have different property names. This is particularly useful for mapping properties during data copying. ```kotlin @CopyTo(DataModel::class) data class DomainModel( @CopyTo.Map("dataId") val domainId: String, ) data class DataModel( val dataId: String, ) // auto genarate fun DomainModel.copyToDataModel( dataId: String = this.domainId, // domainId と dataId がマッピングされます ): DataModel = ... ``` ```kotlin @CopyFrom(DataModel::class) data class DomainModel( @CopyFrom.Map("dataId") val domainId: String, ) data class DataModel( val dataId: String, ) // auto generate fun DataModel.copyToDomainModel( domainId: String = this.dataId, // dataId と domainId がマッピングされます ) ``` -------------------------------- ### Generate Copy Functions Between Classes with @CopyMapping Source: https://context7.com/tbsten/cream/llms.txt This snippet demonstrates how to use the @CopyMapping annotation to generate Kotlin functions that copy data between different data classes. It's particularly useful for integrating with external libraries where you cannot modify the original model classes. The annotation facilitates mapping between source and target classes, and can also handle bidirectional mapping. ```kotlin import me.tbsten.cream.CopyMapping // Library X model (cannot be modified - from external library) data class RetrofitUserResponse( val userId: String, val displayName: String, val avatarUrl: String, ) // Library Y model (cannot be modified - from another external library) data class RoomUserEntity( val userId: String, val displayName: String, val avatarUrl: String, val cachedAt: Long, ) // Your domain model data class User( val userId: String, val displayName: String, val avatarUrl: String, ) // Declare mappings in your own code: @CopyMapping(RetrofitUserResponse::class, User::class) @CopyMapping(User::class, RoomUserEntity::class) private object UserMappings // Generated functions: // fun RetrofitUserResponse.copyToUser(...): User // fun User.copyToRoomUserEntity(...): RoomUserEntity // Usage in repository with multiple libraries: class UserRepository( private val api: RetrofitApiService, private val db: RoomDatabase ) { suspend fun fetchAndCacheUser(userId: String): User { // Fetch from network (Retrofit library): val networkResponse: RetrofitUserResponse = api.getUser(userId) // Convert to domain model: val user: User = networkResponse.copyToUser() // Convert to database entity (Room library) and cache: val entity: RoomUserEntity = user.copyToRoomUserEntity( cachedAt = System.currentTimeMillis() ) db.userDao().insert(entity) return user } } // Example 2: Bidirectional mapping with canReverse parameter data class LibraryAModel(val data: String, val propA: Int) data class LibraryBModel(val data: String, val propB: String) @CopyMapping(LibraryAModel::class, LibraryBModel::class, canReverse = true) private object BidirectionalMapping // Generated functions (both directions): // fun LibraryAModel.copyToLibraryBModel(data: String = this.data, propB: String): LibraryBModel // fun LibraryBModel.copyToLibraryAModel(data: String = this.data, propA: Int): LibraryAModel class DataSynchronizer { fun syncAtoB(modelA: LibraryAModel): LibraryBModel { return modelA.copyToLibraryBModel(propB = modelA.propA.toString()) } fun syncBtoA(modelB: LibraryBModel): LibraryAModel { return modelB.copyToLibraryAModel(propA = modelB.propB.toIntOrNull() ?: 0) } } ``` -------------------------------- ### Map Properties with Different Names using @CopyTo.Map and @CopyFrom.Map Source: https://context7.com/tbsten/cream/llms.txt Annotations `@CopyTo.Map` and `@CopyFrom.Map` facilitate mapping properties with differing names between source and target data classes. `@CopyTo.Map` is used for forward mapping (source to target), while `@CopyFrom.Map` is for reverse mapping (target to source). This annotation requires importing `me.tbsten.cream.CopyTo` and `me.tbsten.cream.CopyFrom`. ```kotlin import me.tbsten.cream.CopyTo import me.tbsten.cream.CopyFrom // Example 1: Using @CopyTo.Map for forward mapping from DomainUser to DatabaseUser @CopyTo(DatabaseUser::class) data class DomainUser( @CopyTo.Map("user_id") val id: String, @CopyTo.Map("user_name") val name: String, @CopyTo.Map("email_address") val email: String, ) data class DatabaseUser( val user_id: String, val user_name: String, val email_address: String, ) // Example 2: Using @CopyFrom.Map for reverse mapping from ApiProduct to Product data class ApiProduct( val product_id: String, val product_name: String, val price_cents: Int, ) @CopyFrom(ApiProduct::class) data class Product( @CopyFrom.Map("product_id") val id: String, @CopyFrom.Map("product_name") val name: String, @CopyFrom.Map("price_cents") val priceInCents: Int, ) // Usage example in a ProductRepository class demonstrating data layer mapping: class ProductRepository(private val api: ProductApi, private val db: ProductDatabase) { suspend fun saveProduct(product: Product) { // Map domain model to database model with snake_case columns: val dbUser = product.copyToDatabaseUser() // Uses generated mapping db.insert(dbUser) } suspend fun getProduct(id: String): Product { // Map API response to domain model: val apiProduct = api.fetchProduct(id) return apiProduct.copyToProduct() // Uses generated mapping } } ``` -------------------------------- ### Automated State Transition with cream.kt Source: https://github.com/tbsten/cream/blob/main/README.ja.md Demonstrates how cream.kt simplifies state transitions by automatically generating copy functions. Instead of manually copying properties, you can use a generated function like `prevState.toSuccess(data = newData)`, making the code cleaner and highlighting new or changed data. ```kotlin // Traditional approach // ❌ It's hard to tell at a glance which data has been added or changed MyUiState.Success( userName = prevState.userName, // Manual copy password = prevState.password, // Manual copy data = newData ) // Using cream.kt // (toSuccess is automatically generated) // ✅ It's clear that data has been added prevState.toSuccess(data = newData) // Automatic copy ``` -------------------------------- ### Generate Copy Functions for Sealed Hierarchies with @CopyToChildren Source: https://github.com/tbsten/cream/blob/main/README.ja.md The @CopyToChildren annotation automatically generates copy functions for all classes inheriting from a sealed class or interface. This eliminates the need to manually annotate each subclass with @CopyTo, significantly reducing boilerplate code. ```kotlin sealed interface UiState { data object Loading : UiState sealed interface Success : UiState { val data: Data data class Done( override val data: Data, ) : Success data class Refreshing( override val data: Data, ) : Success } } // auto generate fun UiState.copyToUiStateSuccessDone( data: Data, ): UiState.Success.Done = /* ... */ fun UiState.copyToUiStateSuccessRefreshing( data: Data, ): UiState.Success.Refreshing = /* ... */ ```