Type mismatch: inferred type is 'Unit' but 'ReviewSubject' was expected

When google on this error, than I realize I’m not first one!
And I’m quite new - except two Udemy courses - to Kotlin but I try to find what’s going on.
It is existing code what I’m were I’m working on:

// In this function occurs the error. (every line is underscored red in IntelliJ)
override fun getReviewtSubject(caseId: CaseId, reviewSubjectId: ReviewSubjectId): ReviewSubject = usingDSL {
        context ->
            context.subjectSelect(caseId)
                .from(REVIEW_SUBJECT)
                .where(REVIEW_SUBJECT.CASE_ID.eq(caseId.value))
                .and(REVIEW_SUBJECT.REVIEWSUBJECT_ID.eq(reviewSubjectId.value))
                .fetchSingle(mapping(::ReviewSubject))
    }
	
   private fun DSLContext.subjectSelect(caseId: CaseId, mainUsage: Boolean? = false) = this.select(
        CASE_SUBJECT.viewSubject.ID.convertFrom { ReviewSubjectId(it!!) },
        CASE_SUBJECT.viewSubject.NAME.convertFrom { it!! },
        CASE_SUBJECT.viewSubject.EXPLANATION.convertFrom { explanation -> explanation?.let { RichText(it) } },
        CASE_SUBJECT.viewSubject.VALIDITY,       // When I add this line I will get the error
//        CASE_SUBJECT.viewSubject.VALIDITY.convertFrom { it?.vanaf },
//        CASE_SUBJECT.viewSubject.VALIDITY.convertFrom { it?.totEnMet },
        beoordelingsgidsProjection(CASE_SUBJECT.Reviewguide),
        if (mainUsage == true) 		// but this is false, so else is executed
           .... code
        else
            DSL.inline(null as mainUsage?),
    )
	
data class ReviewSubject (
    val id: ReviewSubjectId,
    val name: String,
    val explanation: RichText? = null,
    val guide: Reviewguide? = null,
    val validity: String? = null,				// This line is added because I have add this in fun DSLcontext.subjectSelect
//    val beginValidity: LocalDate? = null,         
//    val endValidity: LocalDate?= null,
    val usage: mainUsage? = null,
)

I have to extend the backend query with the field Validity (and later with beginValidity & endValidity).

The first function fun getSubject(…) is called from the front-end API.
This function is calling the DSLContext.subjectSelect(…) called, only with the parameter ‘caseId’.
On the moment that I add the field ‘validity’ which I also define in the data class, then I get the error “Type mismatch: inferred type is Unit but ReviewSubject was expected” for the function fun getReviewtSubject((…).
If change the return type ‘ReviewSubject’ to ‘Unit’, what is suggested by IntelliJ, still get errors!

Also the Jooq lib is used here.
Can anyone give me an idea what is wrong and\or suggestion in which direction I have to search?
I go through the code but I have till now, I have no idea what is wrong, sorry.

In a nutshell, Kotlin is saying you’re doing this:

override fun getReviewtSubject(caseId: CaseId, reviewSubjectId: ReviewSubjectId): ReviewSubject {
    return Unit
}

Now, a lot of your code is missing, so I don’t have a full picture of what’s wrong. However, I would check out your this.select() function.

Another idea is to break your code up into different variables and see exactly where it’s going wrong. Something like this:

val select = context.subjectSelect(caseId)

val from = select.from(REVIEW_SUBJECT)

val where = from.where(REVIEW_SUBJECT.CASE_ID.eq(caseId.value))

val and = where.and(REVIEW_SUBJECT.REVIEWSUBJECT_ID.eq(reviewSubjectId.value))

val single = and.fetchSingle(mapping(::ReviewSubject))

return@usingDSL single

Then you should be able to mouse over each variable and see exactly what type it is. Then you’ll see where you’re going wrong.

However, my guess is that it’s the last line, the fetchSingle; or more specifically, the mapping function. I’m assuming the ::ReviewSubject is a shorthand for providing the constructor as a lambda? So mapping wants a function that takes a bunch of values and returns a ReviewSubject.

In fact, now that I’ve written that out, I reckon you might need to update the mapping function; maybe it doesn’t know how to construct a ReviewSubject now that you’ve added extra fields.

The mapping is JOOQ functionality with Record 5 and Record 6 … 21:

public static final <T1, T2, T3, T4, T5, R extends Record5<T1, T2, T3, T4, T5>, U> RecordMapper<R, U> mapping(
        Function5<? super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? extends U> function
    ) {
        return r -> function.apply(r.value1(), r.value2(), r.value3(), r.value4(), r.value5());
    }

public static final <T1, T2, T3, T4, T5, T6, R extends Record6<T1, T2, T3, T4, T5, T6>, U> RecordMapper<R, U> mapping(
        Function6<? super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? extends U> function
    ) {
        return r -> function.apply(r.value1(), r.value2(), r.value3(), r.value4(), r.value5(), r.value6());
    }

The remarkable thing is that when I add that line then the SelectJoinStep is changed from Record 5 to Record 6. But jooq generated open class still uses Record5<…>

If I hover over the “fetchSingle(…)” method then IntelliJ marked as the error:

fetchSingle(Int) defined in org.jooq.SelectConditionStep
fetchSingle(String!) defined in org.jooq.SelectConditionStep
fetchSingle(Field<TypeVariable(T)!>!)
where T = TypeVariable(T) for
fun <T : Any!> fetchSingle(field: Field<T!>!): T? defined in org.jooq.SelectConditionStep
fetchSingle(Name!) defined in org.jooq.SelectConditionStep
fetchSingle(RecordMapper<in Record6<ReviewSubjectId!, String!, RichText!, Valitity?, Reviewguide!, MainUsage?>!, TypeVariable(E)!>!)
where E = TypeVariable(E) for
fun <E : Any!> fetchSingle(mapper: RecordMapper<in Record6<ReviewSubjectId!, String!, RichText!, Valitity?, Reviewguide!, MainUsage?>!, E!>!): E & Any defined in org.jooq.SelectConditionStep

I don’t think I can help then, sorry; I don’t know anything about the library you’re using.

I don’t understand it till now but it was due the order in the select:
Original:

private fun DSLContext.subjectSelect(caseId: CaseId, mainUsage: Boolean? = false) = this.select(
        CASE_SUBJECT.viewSubject.ID.convertFrom { ReviewSubjectId(it!!) },
        CASE_SUBJECT.viewSubject.NAME.convertFrom { it!! },
        CASE_SUBJECT.viewSubject.EXPLANATION.convertFrom { explanation -> explanation?.let { RichText(it) } },
        CASE_SUBJECT.viewSubject.VALIDITY,       // When I add this line I will get the error
//        CASE_SUBJECT.viewSubject.VALIDITY.convertFrom { it?.vanaf },
//        CASE_SUBJECT.viewSubject.VALIDITY.convertFrom { it?.totEnMet },

Changing to moving VALIDITY at top of Select.

private fun DSLContext.subjectSelect(caseId: CaseId, mainUsage: Boolean? = false) = this.select(
        CASE_SUBJECT.viewSubject.VALIDITY,       // Now it compiles and it works!???r
        CASE_SUBJECT.viewSubject.VALIDITY.convertFrom { it?.vanaf },
        CASE_SUBJECT.viewSubject.VALIDITY.convertFrom { it?.totEnMet },
        CASE_SUBJECT.viewSubject.ID.convertFrom { ReviewSubjectId(it!!) },
        CASE_SUBJECT.viewSubject.NAME.convertFrom { it!! },
        CASE_SUBJECT.viewSubject.EXPLANATION.convertFrom { explanation -> explanation?.let { RichText(it) } }, 

And I have changed the data class

data class ReviewSubject (
    val validity: String? = null,				
    val beginValidity: LocalDate? = null,         
    val endValidity: LocalDate?= null,
    val id: ReviewSubjectId,
    val name: String,
    val explanation: RichText? = null,
    val guide: Reviewguide? = null,
    val usage: mainUsage? = null,
)

It is Jooq issue I think, something with generated classes of Jooq like the ‘SelectionStep’.
I have also (re-) generateJooq task, but that doesn’t bring anything. Only the order and not in way that expected…?

And it is now the order what I do not understand why it should be placed right at the first place of the select!!???

With another table I did the same and added there the VALIDITY fields at the end , it works perfectly.
The difference is there is not fetchSingle(mapper::) used but fetchSingle(<method(“Record”)>), the method is populating the record with the values.

That makes the difference?