R2DBC and enum (PostgreSQL)

穿精又带淫゛_ 提交于 2020-06-01 12:32:27

问题


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.

  1. Define a enum class

    enum class Mood {
        UNKNOWN,
        HAPPY,
        SAD
    }
    
  2. 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
        }
    }
    
  3. Registe the codec

    You may need change runtimeOnly("io.r2dbc:r2dbc-postgresql") to implementation("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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!