问题
Does H2DBC support PostgreSQL enums? I checked they git page but it doesn't mention anything about it. If it does, how enums could be used (INSERT, SELECT)?
Lets say PostgreSQL enum
CREATE TYPE mood AS ENUM ('UNKNOWN', 'HAPPY', 'SAD', ...);
Java class
@Data
public class Person {
private String name;
private Mood mood;
// ...
enum Mood{ UNKNOWN, HAPPY, SAD, ...}
}
I tried:
// insert
var person = ...;
client.insert()
.table("people")
.using(person)
.then()
.subscribe(System.out::println);
// select
var query = "SELECT * FROM people";
client.execute(query)
.as(Person.class)
.fetch().all()
.subscribe(System.out::println);
But I'm getting error messages:
# on insert
WARN [reactor-tcp-epoll-1] (Loggers.java:294) - Error: SEVERITY_LOCALIZED=ERROR, SEVERITY_NON_LOCALIZED=ERROR, CODE=42804, MESSAGE=column "mood" is of type mood but expression is of type character varying, HINT=You will need to rewrite or cast the expression., POSITION=61, FILE=parse_target.c, LINE=591, ROUTINE=transformAssignedExpr
# on select
ERROR [reactor-tcp-epoll-1] (Loggers.java:319) - [id: 0x8581acdb, L:/127.0.0.1:39726 ! R:127.0.0.1/127.0.0.1:5432] Error was received while reading the incoming data. The connection will be closed.
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.data.mapping.MappingException: Could not read property private ...
I found similar post but without luck to solve my problem.. maybe I was applying it wrong..
Any help or tips are welcome.
回答1:
Tested with org.springframework.data:spring-data-r2dbc:1.0.0.RELEASE
and io.r2dbc:r2dbc-postgresql:0.8.1.RELEASE
.
Kotlin version.
Define a enum class
enum class Mood { UNKNOWN, HAPPY, SAD }
Create a custom codec
class MoodCodec(private val allocator: ByteBufAllocator) : Codec<Mood> { override fun canEncodeNull(type: Class<*>): Boolean = false override fun canEncode(value: Any): Boolean = value is Mood override fun encode(value: Any): Parameter { return Parameter(Format.FORMAT_TEXT, oid) { ByteBufUtils.encode(allocator, (value as Mood).name) } } override fun canDecode(dataType: Int, format: Format, type: Class<*>): Boolean = dataType == oid override fun decode(buffer: ByteBuf?, dataType: Int, format: Format, type: Class<out Mood>): Mood? { buffer ?: return null return Mood.valueOf(ByteBufUtils.decode(buffer)) } override fun type(): Class<*> = Mood::class.java override fun encodeNull(): Parameter = Parameter(Format.FORMAT_TEXT, oid, Parameter.NULL_VALUE) companion object { // Get form `select oid from pg_type where typname = 'mood'` private const val oid = YOUR_ENUM_OID } }
Registe the codec
You may need change
runtimeOnly("io.r2dbc:r2dbc-postgresql")
toimplementation("io.r2dbc:r2dbc-postgresql")
@Configuration @EnableR2dbcRepositories class AppConfig : AbstractR2dbcConfiguration() { override fun connectionFactory(): ConnectionFactory = PostgresqlConnectionConfiguration.builder() .port(5432) // Add your config here. .codecRegistrar { _, allocator, registry -> registry.addFirst(MoodCodec(allocator)) Mono.empty() }.build() .let { PostgresqlConnectionFactory(it) } }
来源:https://stackoverflow.com/questions/60084867/r2dbc-and-enum-postgresql