How do you provide client-side audit information to jOOQ?

Issue

I’m not entirely sure how to populate the Audit Columns I specify in my project.

I configured a integer-type user id as my "user" column:

ForcedType().apply {
    isAuditUpdateUser = true
    name = "int"
    includeExpression = "last_modifier"
},
ForcedType().apply {
    isAuditUpdateTimestamp = true
    name = "timestamptz"
    includeExpression = "last_modified"
}

To quote the documentation:

All such audit columns compute their actual value from Configuration.auditProvider(), which allows for overriding the org.jooq.impl.DefaultAuditProvider behaviour

So I was expecting to be able to declare a configuration like this in the server module:

@Configuration
class JooqConfig(
    private val principalService: PrincipalService, //has access to spring security context
) {
    @Bean
    fun configurationCustomizer() = DefaultConfigurationCustomizer { c: DefaultConfiguration ->
        c.setAuditProvider(auditProvider())
    }

    @Bean
    fun auditProvider(): AuditProvider = PrincipalAwareAuditProvider(principalService)

    private class PrincipalAwareAuditProvider(private val principalService: PrincipalService) : DefaultAuditProvider(){

        override fun <T : Any?> provideUser(ctx: GeneratorContext<*, *, T>): Field<T>? {
            val userId = principalService.currentUserId()
            return ctx.field()?.let { field ->
                when(field.dataType.type){
                    Int::class.java -> TODO("do something with userId")
                    else -> null
                }
            }
        }

        override fun <T : Any?> provideTimestamp(ctx: GeneratorContext<*, *, T>?): Field<T>? {
            TODO("figure out what to do about this")
        }

    }
}

BUT I’m not sure how or why to create a Field out of the userId.
Am I trying to do this in the wrong place?

How do I fill the audit columns with values?

Solution

The point of returning a Field<T> (an expression) rather than just the value T (a client side value) is, well, to allow for creating expressions.

Imagine you’re using e.g. Oracle’s SYS_CONTEXT to populate contextual values like that directly from within the database. How could you possibly access SYS_CONTEXT expressions if this SPI didn’t allow you to provide a Field<T>?

If your value is purely client side generated, then just wrap it in a bind value, explicitly. But a bind value is just a special case of the more generic case where you produce server side expressions.

Answered By – Lukas Eder

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published