Insert a row into Room using Rxjava on Kotlin - kotlin

This article says that I can use Completable as return type for #Insert
But as I do that, the error occured:
error: local variable pointToInsert is accessed from within inner class; needs to be declared final
This error happens with AndoridX since Rxjava return types support included only since 2.1 version : https://issuetracker.google.com/issues/63317956#comment25
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertPoint(pointToInsert: ControlPoint): Completable
So, how to make this thing work?

As this feature is completely unavailable unless you use version 2.1+, you can actually solve this problem using lower version by making some kind of adapter for you DAO:
#Dao
interface Original {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertPoint(pointToInsert: ControlPoint)
}
class AdHocCompletableAdapter(private val dao: Original) {
fun insertPoint(pointToInsert: ControlPoint) =
Completable.create {
dao.insertPoint(pointToInsert)
it.onComplete()
}
}
Or create some more flexible solution (using, for instance, function composition).

Related

When I use the generic method in Route then I am getting compiler Backend Internal error: Exception during IR lowering in Ktor

I am trying to create a dynamic service based on the data class model defined by user and they registerDataModels() method appDataModule() it should automatically create all based method in the router service. When I try to achive using generics in those method I am getting a compiler error. Is there any other better way to dynamically create route methods like by defining the datamodel by developer and then service should be automatically created?
org.jetbrains.kotlin.backend.common.BackendException: Backend Internal error: Exception during IR lowering
File being compiled: */api/AppConfigService.kt
The root cause java.lang.RuntimeException was thrown at: org.jetbrains.kotlin.backend.jvm.codegen.FunctionCodegen.generate(FunctionCodegen.kt:47)
File is unknown
The root cause java.lang.AssertionError was thrown at: org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor.spillVariables(CoroutineTransformerMethodVisitor.kt:636)
fun Application.registerDataModels() {
appDataModule<M1>()
appDataModule<M2>()
appDataModule<M3>()
}
inline fun <reified T: DBModel> Application.appDataModule() {
routing {
createAppData<T>()
updateAppData<T>()
deleteAppData<T>()
}
}
inline fun <reified T: DBModel> Route.createAppData() {
put("/api/data/${getName<T>()}/create") {
authenticated {
create<T>{}
}
}
}
inline fun <reified T: DBModel> Route.updateAppData() {
put("/api/data/${getName<T>()}/update") {
authenticated {
update<T>{}
}
}
}
inline fun <reified T: DBModel> Route.deleteAppData() {
put("/api/data/${getName<T>()}/delete") {
authenticated {
delete<T>{}
}
}
}
Note: This answer assumed that code would be loaded at runtime, which seems not to be the case, and is therefore not completely matching OP's question.
You are using inline functions with reified.
To make a long story short, inline functions are compiled and 'copied' to the location where they are being used, already with a fixed (thats what reified does) class. So when you use an inline function
inline fun <reified T> foo(t: T): T { ... }
and you call it like this:
val myVal = foo("test").uppercase()
then at compile time of that calling line of code, the type of T is known to be String and the target line is compiled accordingly, so you know at runtime which type T is within your function.
It is (for this one calling line) as if that function was like this to begin with:
fun foo(t: String): String { ... }
Because you want to compile these classes dynamically, however, this process fails, because the class obviously does not exist yet. This is simply due to the nature of reified. If you can somehow remove it, it might work.
I agree that the error message of the compiler could be more telling here. Maybe you can raise a task on kotlin's issue tracking platform?: https://youtrack.jetbrains.com/issues/kt?_gl=1*5r6x4d*_ga*MTQyMDYxMjc2MS4xNjMzMzQwMzk5*_ga_9J976DJZ68*MTY2OTM1NjM1MS4yMS4xLjE2NjkzNTYzNTcuMC4wLjA.&_ga=2.265829455.1332696793.1669356352-1420612761.1633340399

How to create a Serializer for a List<Pair<String, Any>>

I'm trying to create a Serializer for the List<Pair<String, Any>> type, I need this type for a project where I have to manipulate keys and values but user can change key names at any time and using a List of Pair is much better for what I want (and doesn't really work with a Map).
I have this code, but it produces a compiler error
class SnapshotListPairSerializer<K, V>(private val keySerializer: KSerializer<K>, private val valueSerializer: KSerializer<V>) :
KSerializer<SnapshotStateList<Pair<K, V>>> {
override val descriptor: SerialDescriptor = ListSerializer(PairSerializer(keySerializer, valueSerializer)).descriptor
override fun serialize(encoder: Encoder, value: SnapshotStateList<Pair<K, V>>) {
encoder.encodeSerializableValue(ListSerializer(PairSerializer(keySerializer, valueSerializer)), value as List<Pair<K, V>>)
}
override fun deserialize(decoder: Decoder): SnapshotStateList<Pair<K, V>> {
val list = mutableStateListOf<Pair<K, V>>()
val items = decoder.decodeSerializableValue(ListSerializer(PairSerializer(keySerializer, valueSerializer)))
list.addAll(items)
return list
}
}
Also, SnapshotStateList is a class that comes from Jetpack Compose and extends List.
The exception you get is:
Backend Internal error: Exception during IR lowering
Given that this is not providing you with meaningful information, but mentions compiler internals, this is not an error of your doing, but a bug: a cue to search for known bugs.
This seems very similar to the issue I filed on GitHub.
If it is the same cause, it should be fixed in version 1.6.10. This may explain why Philip can't repro.
P.s. the next problem you will run into is likely that Any is not registered for polymorphic serialization. Serializing Any is dodgy. If you are stuck and the documentation does not help you out, I suggest you post a new question with more information on the exact use case/expected types, and I will gladly help out.

Join eq function not working with Jooq and Kotlin

I'm using:
Jooq 3.13.2
Kotlin 1.3.71
Spring boot 2.2.6.RELESE
Java 11
I was able to generate Jooq classes and execute a simple query:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.forEach { println($it[STORY.ID]) }
}
}
When I try to add a bit more complex logic by adding join, compilation is failing:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
.forEach { println($it[STORY.ID]) }
}
}
Compilation fails on following line .join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
Error:
None of the following functions can be called with the arguments supplied:
public abstract fun eq(p0: Int!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Field<Int!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: QuantifiedSelect<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Select<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
I was following this tutorial: https://blog.jooq.org/2017/05/18/10-nice-examples-of-writing-sql-in-kotlin-with-jooq/
Edit:
It looks like the issue is that STORY.CREATED_BY is type of Long, while USERS.ID is type of Integer. I'm not sure what needs to be changed to be able to fix this.
Thank you
You should probably change the type of all of these ID columns and their reference to be the same, i.e. BIGINT.
As a quick workaround, you can use Field.coerce(). I would prefer that over Field.cast(). The difference is that coerce() does not have any effect on the generated SQL (which you want to avoid to get better index usage), whereas cast() translates to the SQL CAST() function.

why there is 'by' for the extended class and reified in function define

coming across a sample with a class and a function and trying to understand the koltin syntax there,
what does this IMeta by dataItem do? looked at https://kotlinlang.org/docs/reference/classes.html#classes and dont see how to use by in the derived class
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
class DerivedStreamItem(private val dataItem: IMeta, private val dataType: String?) :
IMeta by dataItem {
override fun getType(): String = dataType ?: dataItem.getType()
fun getData(): DerivedData? = getDataItem()
private inline fun <reified T> getDataItem(): T? = if (dataItem is T) dataItem else null
}
for the reference, copied the related defines here:
interface IMeta {
fun getType() : String
fun getUUIDId() : String
fun getDataId(): String?
}
class DerivedData : IMeta {
override fun getType(): String {
return "" // stub
}
override fun getUUIDId(): String {
return "" // stub
}
override fun getDataId(): String? {
return "" // stub
}
}
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
There is some good documentation on reified type parameters, but I'll try to boil it down a bit.
The reified keyword in Kotlin is used to get around the fact that the JVM uses type erasure for generic. That means at runtime whenever you refer to a generic type, the JVM has no idea what the actual type is. It is a compile-time thing only. So that T in your example... the JVM has no idea what it means (without reification, which I'll explain).
You'll notice in your example that you are also using the inline keyword. That tells Kotlin that rather than call a function when you reference it, to just insert the body of the function inline. This can be more efficient in certain situations. So, if Kotlin is already going to be copying the body of our function at compile time, why not just copy the class that T represents as well? This is where reified is used. This tells Kotlin to refer to the actual concrete type of T, and only works with inline functions.
If you were to remove the reified keyword from your example, you would get an error: "Cannot check for instance of erased type: T". By reifying this, Kotlin knows what actual type T is, letting us do this comparison (and the resulting smart cast) safely.
(Since you are asking two questions, I'm going to answer them separately)
The by keyword in Kolin is used for delegation. There are two kinds of delegation:
1) Implementation by Delegation (sometimes called Class Delegation)
This allows you to implement an interface and delegate calls to that interface to a concrete object. This is helpful if you want to extend an interface but not implement every single part of it. For example, we can extend List by delegating to it, and allowing our caller to give us an implementation of List
class ExtendedList(someList: List) : List by someList {
// Override anything from List that you need
// All other calls that would resolve to the List interface are
// delegated to someList
}
2) Property Delegation
This allows you to do similar work, but with properties. My favorite example is lazy, which lets you lazily define a property. Nothing is created until you reference the property, and the result is cached for quicker access in the future.
From the Kotlin documentation:
val lazyValue: String by lazy {
println("computed!")
"Hello"
}

Room migration fails without error

i'm working with Room and suddenly it stops to show errors when i changed one or more entities. For example i add one field (vendor: String) to my Entity and it just clear all data without any error or suggestions. Just clearing all data and stop working. I don't use fallbackToDestructiveMigration.
Please help i really don't know how to avoid this. All of my branches wait for db sync.
Here is the code
#Database(entities = [(ServiceEntity::class), (ConfigEntity::class), (RequestEntity::class), (FaqEntity::class),
(SubscriptionEntity::class), (OrderEntity::class), (DeviceEntity::class), (ProblemEntity::class)], version = 5,
exportSchema = true)
abstract class RoomAppDataSource: RoomDatabase() {
abstract fun serviceDao(): ServiceDao
abstract fun configDao(): ConfigDao
abstract fun requestDao(): RequestDao
abstract fun otherDao(): OtherDao
abstract fun subscriptionsDao(): SubscriptionsDao
abstract fun ordersDao(): OrdersDao
companion object {
private val TAG = RoomAppDataSource::class.java.simpleName
private val Migration_4_5 = object: Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE ${RoomContract.TABLE_SERVICES} ADD COLUMN vendor TEXT default '' NOT NULL")
}
}
fun buildDataSource(context: Context): RoomAppDataSource = Room.databaseBuilder(
context.applicationContext, RoomAppDataSource::class.java, RoomContract.DATABASE_APP)
.addMigrations(Migration_4_5)
.build()
}
}
P.S. If i remove new line it works fine, but when i add smth in any entity app starts from tutorial page, because there are no tokens saved
Found an answer. I don't know why, but room just stop asserting new version of db or destructive migrations, so error i can see only when use Dao funcs. May be it will help to someone.