Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R2DBC: Generated query SQL neglects custom column names #1624

Open
sunny-chung opened this issue Sep 26, 2023 · 4 comments
Open

R2DBC: Generated query SQL neglects custom column names #1624

sunny-chung opened this issue Sep 26, 2023 · 4 comments
Assignees
Labels
for: team-attention An issue we need to discuss as a team to make progress in: r2dbc Spring Data R2DBC status: pending-design-work Needs design work before any code can be developed

Comments

@sunny-chung
Copy link

sunny-chung commented Sep 26, 2023

Not sure if this is the right place to report a R2DBC issue.

I have a spring data repository like this:

interface ChatChannelParticipantRepository : BaseRepository<ChatChannelParticipant> {

    suspend fun countByChannelIdAndUserIdAndActive(channelId: String, userId: String, active: Boolean): Long
}

@NoRepositoryBean
interface BaseRepository<T : BaseEntity> : CoroutineCrudRepository<T, String>

Entities like this:

@Table(name = "message__chat_channel_participant")
data class ChatChannelParticipant(
    val channelId: String,
    val userId: String,
    val role: Role
) : BaseEntity()

abstract class BaseEntity {
    @Id
    var id: String = UUID.randomUUID().toString()

    @Column(value = "is_active")
    var isActive: Boolean = true
}

When I execute the query defined in the repository, I got this exception:

org.springframework.r2dbc.BadSqlGrammarException: executeMany; bad SQL grammar [SELECT COUNT(message__chat_channel_participant.id) FROM message__chat_channel_participant WHERE message__chat_channel_participant.channel_id = ? AND (message__chat_channel_participant.user_id = ?) AND (message__chat_channel_participant.active = ?)]
	at org.springframework.r2dbc.connection.ConnectionFactoryUtils.convertR2dbcException(ConnectionFactoryUtils.java:243) ~[spring-r2dbc-6.0.11.jar!/:6.0.11]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
	*__checkpoint ⇢ Handler com.example.api.MessageApi#list(String, Instant, Instant, int, String, Continuation) [DispatcherHandler]
Original Stack Trace:
		at org.springframework.r2dbc.connection.ConnectionFactoryUtils.convertR2dbcException(ConnectionFactoryUtils.java:243) ~[spring-r2dbc-6.0.11.jar!/:6.0.11]
		at org.springframework.r2dbc.core.DefaultDatabaseClient.lambda$inConnectionMany$8(DefaultDatabaseClient.java:151) ~[spring-r2dbc-6.0.11.jar!/:6.0.11]
		at reactor.core.publisher.Flux.lambda$onErrorMap$28(Flux.java:7236) ~[reactor-core-3.5.9.jar!/:3.5.9]

...

Caused by: io.r2dbc.spi.R2dbcBadGrammarException: Unknown column 'message__chat_channel_participant.active' in 'where clause'
	at io.asyncer.r2dbc.mysql.message.server.ErrorMessage.toException(ErrorMessage.java:108) ~[r2dbc-mysql-1.0.2.jar!/:1.0.2]
	at io.asyncer.r2dbc.mysql.message.server.ErrorMessage.toException(ErrorMessage.java:73) ~[r2dbc-mysql-1.0.2.jar!/:1.0.2]
	at io.asyncer.r2dbc.mysql.MySqlResult$MySqlMessage.exception(MySqlResult.java:185) ~[r2dbc-mysql-1.0.2.jar!/:1.0.2]
	at io.asyncer.r2dbc.mysql.MySqlResult.lambda$map$1(MySqlResult.java:99) ~[r2dbc-mysql-1.0.2.jar!/:1.0.2]
	at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:113) ~[reactor-core-3.5.9.jar!/:3.5.9]
	at reactor.core.publisher.FluxHandle$HandleConditionalSubscriber.onNext(FluxHandle.java:343) ~[reactor-core-3.5.9.jar!/:3.5.9]
	at reactor.core.publisher.FluxContextWriteRestoringThreadLocals$ContextWriteRestoringThreadLocalsSubscriber.onNext(FluxContextWriteRestoringThreadLocals.java:116) ~[reactor-core-3.5.9.jar!/:3.5.9]
	at io.asyncer.r2dbc.mysql.internal.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:66) ~[r2dbc-mysql-1.0.2.jar!/:1.0.2]
	at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:670) ~[reactor-core-3.5.9.jar!/:3.5.9]

...

The result is the same regardless of the existence of the @Column annotation.

Versions:
Kotlin 1.8.22
JVM Target 17
Spring Data Commons 3.1.2
Spring Data R2dbc 3.1.2

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 26, 2023
@mp911de
Copy link
Member

mp911de commented Sep 26, 2023

You do not use the property that you think you're using.

The property is declared with the name isActive while your query method uses a property named active. Kotlin renders a method isActive that introduces another property with the name active but without the annotation as the annotation resides at the field isActive.

This is an unfortunate arrangement as you end up with two properties without an obvious way to detect that mismatch.

@mp911de mp911de added the for: team-attention An issue we need to discuss as a team to make progress label Sep 26, 2023
@sunny-chung
Copy link
Author

sunny-chung commented Sep 27, 2023

Yes, it works if I change to countByChannelIdAndUserIdAndIsActive.

JetBrains' Spring Data plugin incorrectly reports the property "isActive" cannot be resolved, and only "Active" is available for autocompletion. But this has nothing to do with Spring Data.

Could Spring Data include a boolean property as an example in the Kotlin support section of the documentation?

And, for a Kotlin boolean property named isXxx, would Spring Data consider to drop supporting Xxx as a property?

@mp911de
Copy link
Member

mp911de commented Sep 28, 2023

Is there some Kotlin documentation that explains isFoo to Foo property name rewriting?

@sunny-chung
Copy link
Author

This?

https://kotlinlang.org/docs/java-to-kotlin-interop.html#properties

If the name of the property starts with is, a different name mapping rule is used: the name of the getter will be the same as the property name, and the name of the setter will be obtained by replacing is with set. For example, for a property isOpen, the getter will be called isOpen() and the setter will be called setOpen(). This rule applies for properties of any type, not just Boolean.

But I guess we are focusing on Kotlin native support, not Java compatibility.

@mp911de mp911de added status: pending-design-work Needs design work before any code can be developed and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 23, 2023
@schauder schauder added the in: r2dbc Spring Data R2DBC label Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: team-attention An issue we need to discuss as a team to make progress in: r2dbc Spring Data R2DBC status: pending-design-work Needs design work before any code can be developed
Projects
None yet
Development

No branches or pull requests

4 participants