Skip to content

Commit 8b6e7c6

Browse files
jbellassaimp911de
authored andcommitted
Add codecs for working with enums as Strings
Automatically register an EnumStringCodec and an EnumStringArrayCodec for enums. [#454][resolves #429]
1 parent 43c14fa commit 8b6e7c6

File tree

2 files changed

+130
-2
lines changed

2 files changed

+130
-2
lines changed

src/test/java/io/r2dbc/postgresql/codec/EnumCodecIntegrationTests.java

+122
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import io.r2dbc.postgresql.PostgresqlConnectionConfiguration;
2121
import io.r2dbc.postgresql.PostgresqlConnectionFactory;
2222
import io.r2dbc.postgresql.api.PostgresqlConnection;
23+
import io.r2dbc.postgresql.api.PostgresqlResult;
24+
import io.r2dbc.spi.Parameters;
25+
import org.junit.jupiter.api.BeforeAll;
2326
import org.junit.jupiter.api.Test;
2427
import reactor.test.StepVerifier;
2528

@@ -28,6 +31,20 @@
2831
*/
2932
final class EnumCodecIntegrationTests extends AbstractIntegrationTests {
3033

34+
@BeforeAll
35+
static void createEnum() {
36+
try {
37+
SERVER.getJdbcOperations().execute("CREATE TYPE my_enum AS ENUM ('HELLO', 'WORLD')");
38+
} catch (DataAccessException e) {
39+
// ignore duplicate types
40+
}
41+
}
42+
43+
@Override
44+
protected void customize(PostgresqlConnectionConfiguration.Builder builder) {
45+
builder.codecRegistrar(EnumCodec.builder().withEnum("my_enum", MyEnum.class).build());
46+
}
47+
3148
@Test
3249
void shouldReportUnresolvableTypes() {
3350

@@ -46,6 +63,111 @@ void shouldReportUnresolvableTypes() {
4663
// we cannot really assert logs so that's up to you.
4764
}
4865

66+
@Test
67+
void shouldBindEnumTypeAsString() {
68+
69+
SERVER.getJdbcOperations().execute("DROP TABLE IF EXISTS enum_test");
70+
SERVER.getJdbcOperations().execute("CREATE TABLE enum_test (the_value my_enum);");
71+
72+
PostgresTypes types = PostgresTypes.from(this.connection);
73+
PostgresTypes.PostgresType type = types.lookupType("my_enum").block();
74+
75+
this.connection.createStatement("INSERT INTO enum_test VALUES($1)")
76+
.bind("$1", Parameters.in(type, "HELLO"))
77+
.execute()
78+
.flatMap(PostgresqlResult::getRowsUpdated)
79+
.as(StepVerifier::create)
80+
.expectNext(1)
81+
.verifyComplete();
82+
83+
String result = SERVER.getJdbcOperations().queryForObject("SELECT the_value FROM enum_test", String.class);
84+
assertThat(result).isEqualTo("HELLO");
85+
86+
this.connection.createStatement("SELECT * FROM enum_test")
87+
.execute()
88+
.flatMap(it -> it.map(((row, rowMetadata) -> row.get(0, MyEnum.class))))
89+
.as(StepVerifier::create)
90+
.consumeNextWith(actual -> {
91+
assertThat(actual).isEqualTo(MyEnum.HELLO);
92+
})
93+
.verifyComplete();
94+
95+
this.connection.createStatement("SELECT * FROM enum_test")
96+
.execute()
97+
.flatMap(it -> it.map(((row, rowMetadata) -> row.get(0, String.class))))
98+
.as(StepVerifier::create)
99+
.consumeNextWith(actual -> {
100+
assertThat(actual).isEqualTo("HELLO");
101+
})
102+
.verifyComplete();
103+
}
104+
105+
@Test
106+
void shouldBindEnumArrayTypeAsString() {
107+
108+
SERVER.getJdbcOperations().execute("DROP TABLE IF EXISTS enum_test");
109+
SERVER.getJdbcOperations().execute("CREATE TABLE enum_test (the_value my_enum[]);");
110+
111+
PostgresTypes types = PostgresTypes.from(this.connection);
112+
PostgresTypes.PostgresType type = types.lookupType("my_enum").block().asArrayType();
113+
114+
this.connection.createStatement("INSERT INTO enum_test VALUES($1)")
115+
.bind("$1", Parameters.in(type, new String[]{"HELLO", "WORLD"}))
116+
.execute()
117+
.flatMap(PostgresqlResult::getRowsUpdated)
118+
.as(StepVerifier::create)
119+
.expectNext(1)
120+
.verifyComplete();
121+
122+
String result = SERVER.getJdbcOperations().queryForObject("SELECT the_value FROM enum_test", String.class);
123+
assertThat(result).isEqualTo("{HELLO,WORLD}");
124+
125+
this.connection.createStatement("SELECT the_value FROM enum_test")
126+
.execute()
127+
.flatMap(it -> it.map(((row, rowMetadata) -> row.get(0, String[].class))))
128+
.as(StepVerifier::create)
129+
.consumeNextWith(actual -> {
130+
assertThat(actual).contains("HELLO", "WORLD");
131+
})
132+
.verifyComplete();
133+
}
134+
135+
@Test
136+
void shouldBindEnumArrayType() {
137+
138+
SERVER.getJdbcOperations().execute("DROP TABLE IF EXISTS enum_test");
139+
SERVER.getJdbcOperations().execute("CREATE TABLE enum_test (the_value my_enum[]);");
140+
141+
this.connection.createStatement("INSERT INTO enum_test VALUES($1)")
142+
.bind("$1", MyEnum.values())
143+
.execute()
144+
.flatMap(PostgresqlResult::getRowsUpdated)
145+
.as(StepVerifier::create)
146+
.expectNext(1)
147+
.verifyComplete();
148+
149+
this.connection.createStatement("SELECT * FROM enum_test")
150+
.execute()
151+
.flatMap(it -> it.map(((row, rowMetadata) -> row.get(0))))
152+
.as(StepVerifier::create)
153+
.consumeNextWith(actual -> {
154+
155+
assertThat(actual).isInstanceOf(MyEnum[].class);
156+
assertThat((MyEnum[]) actual).contains(MyEnum.values());
157+
158+
})
159+
.verifyComplete();
160+
161+
this.connection.createStatement("SELECT * FROM enum_test")
162+
.execute()
163+
.flatMap(it -> it.map(((row, rowMetadata) -> row.get(0, MyEnum[].class))))
164+
.as(StepVerifier::create)
165+
.consumeNextWith(actual -> {
166+
assertThat(actual).contains(MyEnum.values());
167+
})
168+
.verifyComplete();
169+
}
170+
49171
enum MyEnum {
50172
HELLO;
51173
}

src/test/java/io/r2dbc/postgresql/codec/EnumCodecUnitTests.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import static org.mockito.Mockito.any;
4242
import static org.mockito.Mockito.mock;
4343
import static org.mockito.Mockito.never;
44-
import static org.mockito.Mockito.only;
4544
import static org.mockito.Mockito.times;
4645
import static org.mockito.Mockito.verify;
4746

@@ -72,9 +71,14 @@ void canDecode() {
7271
assertThat(codec.canDecode(1, Format.FORMAT_TEXT, MyEnum.class)).isTrue();
7372
assertThat(codec.canDecode(1, FORMAT_BINARY, MyEnum.class)).isTrue();
7473
assertThat(codec.canDecode(1, FORMAT_BINARY, Object.class)).isTrue();
74+
7575
assertThat(codec.canDecode(VARCHAR.getObjectId(), FORMAT_BINARY, MyEnum.class)).isFalse();
7676
assertThat(codec.canDecode(JSON.getObjectId(), FORMAT_TEXT, MyEnum.class)).isFalse();
7777
assertThat(codec.canDecode(JSONB.getObjectId(), FORMAT_BINARY, MyEnum.class)).isFalse();
78+
79+
EnumCodec.EnumStringCodec stringCodec =
80+
new EnumCodec.EnumStringCodec(TestByteBufAllocator.TEST, 1);
81+
assertThat(stringCodec.canDecode(1, FORMAT_TEXT, String.class)).isTrue();
7882
}
7983

8084
@Test
@@ -110,7 +114,8 @@ void shouldRegisterCodecAsFirst() {
110114
Publisher<Void> register = codecRegistrar.register(mockPostgresqlConnection, mockByteBufAllocator, mockCodecRegistry);
111115
StepVerifier.create(register).verifyComplete();
112116

113-
verify(mockCodecRegistry, only()).addFirst(any(EnumCodec.class));
117+
verify(mockCodecRegistry).addFirst(any(EnumCodec.class));
118+
verify(mockCodecRegistry).addFirst(any(EnumCodec.EnumStringCodec.class));
114119
verify(mockCodecRegistry, never()).addLast(any(EnumCodec.class));
115120
}
116121

@@ -148,6 +153,7 @@ void shouldRegisterCodecAsLast() {
148153

149154
verify(mockCodecRegistry, never()).addFirst(any(EnumCodec.class));
150155
verify(mockCodecRegistry, times(2)).addLast(any(EnumCodec.class));
156+
verify(mockCodecRegistry, times(2)).addLast(any(EnumCodec.EnumStringCodec.class));
151157
}
152158

153159
enum MyEnum {

0 commit comments

Comments
 (0)