Skip to content

Commit

Permalink
Merge pull request #219 from modelix/bugfix/cce-nullIfEmpty
Browse files Browse the repository at this point in the history
fix(modelql): .nullIfEmpty() caused a CCE in some cases
  • Loading branch information
slisson authored Aug 30, 2023
2 parents 45f6358 + c7f02cf commit 5de181c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,30 @@
*/
package org.modelix.modelql.core

import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEmpty
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.nullable
import kotlinx.serialization.modules.SerializersModule

class NullIfEmpty<E>() : MonoTransformingStep<E, E?>() {

override fun getOutputSerializer(serializersModule: SerializersModule): KSerializer<out IStepOutput<E?>> {
val serializer: KSerializer<IStepOutput<E>> = getProducer().getOutputSerializer(serializersModule).upcast()
val valueSerializer = (serializer as SimpleStepOutputSerializer<E>).valueSerializer
val nullableValueSerializer = (valueSerializer as KSerializer<Any>).nullable as KSerializer<E?>
return nullableValueSerializer.stepOutputSerializer(this)
return MultiplexedOutputSerializer(
this,
listOf(
getProducer().getOutputSerializer(serializersModule).upcast(),
nullSerializer<E?>().stepOutputSerializer(this).upcast(),
),
)
}

override fun createFlow(input: StepFlow<E>, context: IFlowInstantiationContext): StepFlow<E?> {
val downcast: StepFlow<E?> = input
return downcast.onEmpty { emit((null as E?).asStepOutput(this@NullIfEmpty)) }
return downcast.map { MultiplexedOutput(0, it) }.onEmpty {
emit(MultiplexedOutput(1, null.asStepOutput(this@NullIfEmpty)))
}
}

override fun transform(evaluationContext: QueryEvaluationContext, input: E): E? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,22 @@ class ModelQLTest {
assertEquals(flowSize, sequenceSize)
}

@Test
fun test_firstOrNull_nullIfEmpty() = runTestWithTimeout {
val result = remoteProductDatabaseQuery { db ->
db.products.firstOrNull().nullIfEmpty()
}
assertEquals(testDatabase.products.firstOrNull(), result)
}

@Test
fun test_nullIfEmpty() = runTestWithTimeout {
val result = remoteProductDatabaseQuery { db ->
db.products.nullIfEmpty().toList()
}
assertEquals(testDatabase.products, result)
}

// @Test
// fun testIndexLookup() {
// val result = remoteProductDatabaseQuery { db ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class PerformanceTests {
val query = buildMonoQuery<Int, Int> { it.filter { it.equalTo(0) } }
val intRange = 1..100000

compareBenchmark(100, 10.0, {
compareBenchmark(100, 20.0, {
query.asSequence(QueryEvaluationContext.EMPTY, intRange.asSequence()).count()
}, {
intRange.asSequence().filter { it == 0 }.count()
Expand Down

0 comments on commit 5de181c

Please sign in to comment.