Search code examples
androidkotlinretrofitandroid-room

Room how to type convert a really complex data class?


I want to use Room database to store data about my Itineraries, but the problem is that my Itinerary data class is really complex due to the large amount of data from API call. What is an optimal way of writing type converter for these types of classes?

Main class stored in Room

data class ItineraryModel(
    @PrimaryKey(autoGenerate = true)
    val itineraryId: Int = 0,

    @ColumnInfo(name = "price_details")
    @TypeConverters(PriceDetailsModelConverter::class)
    val priceDetails: PriceDetailsModel? = null,

    @ColumnInfo(name = "slice_data")
    @TypeConverters(SliceDataModelConverter::class)
    val sliceData: SliceDataModel? = null
)

SliceDataModel

data class SliceDataModel(
    val slice: SliceModel
)

SliceModel

data class SliceModel(
    val info: InfoSliceModel,
    val airline: AirlineModel,
    val arrival: ArrivalModel,
    val departure: DepartureModel,
    val flightData: FlightDataModel
)

InfoSliceModel

data class InfoSliceModel(
    val connectionCount: Int,
    val duration: String,
    val id: Int,
    val stopCount: Int
)

AirlineModel

data class AirlineModel(
    val logo: String,
    val name: String
)

Arrival/Departure Models (the same)

data class ArrivalModel(
    val airport: AirportModel,
    val datetime: DatetimeModel
)

AirportModel

data class AirportModel(
    val city: String,
    val code: String,
    val country: String,
    val name: String,
)

DatetimeModel

data class DatetimeModel(
    val date: String,
    val dateDisplay: String,
    val time24h: String,
)

FlightDataModel

data class FlightDataModel(
    val flights: List<FlightModel>
)

FlightModel

data class FlightModel(
    val arrival: ArrivalModel,
    val departure: DepartureModel,
    val info: InfoModel
)

InfoModel

data class InfoModel(
    val aircraft: String,
    val aircraftType: String,
    val cabinClass: String,
    val cabinName: String,
    val duration: String,
    val stopCount: Int
)

As you can see, there's a lot of data. How can I convert it optimally?


Solution

  • One easy solution to this is to use a serialization library, which allows converting big and complex objects into a String JSON, so you can store them in your Room database easily. I recommend using Kotlinx.serialization library, you can follow this link to setup with Gradle.

    After installing the library, annotate all your data class with @Serializable. For example:

    @Serializable
    @Entity
    data class ItineraryModel(
        @PrimaryKey(autoGenerate = true)
        val itineraryId: Int = 0,
    
        @ColumnInfo(name = "price_details")
        @TypeConverters(PriceDetailsModelConverter::class)
        val priceDetails: PriceDetailsModel? = null,
    
        @ColumnInfo(name = "slice_data")
        @TypeConverters(SliceDataModelConverter::class)
        val sliceData: SliceDataModel? = null
    )
    

    Do the same thing with all other data classes that are involved in your model. After doing this, go to your type converters:

    PriceDetailsModelConverter:

    class PriceDetailsModelConverter {
    
        @TypeConverter
        fun convertToJsonString(priceDetails: PriceDetailsModel?): String {
             return Json.encodeToString(priceDetails)
        }
    
        @TypeConverter
        fun convertToObject(json: String): PriceDetailsModel? {
             return Json.decodeFromString(json)
        }
    
    }
    

    SliceDataModelConverter:

    class SliceDataModelConverter {
    
        @TypeConverter
        fun convertToJsonString(sliceDetails: SliceDataModel?): String {
             return Json.encodeToString(sliceDetails)
        }
    
        @TypeConverter
        fun convertToObject(json: String): SliceDataModel? {
             return Json.decodeFromString(json)
        }
    
    }
    

    And everything is OK, when store the big model object, priceDetails and sliceDetails will be stored in the form of String JSON, when you query the database, you will receive them as model objects.

    Later on, if you want to select rows based on a price condition for example, you have to use LIKE sql operator since the priceDetails is stored as String, this maybe the only drawback of this approach.