Skip to content

Commit 961e670

Browse files
authored
add enum support for mssql (#637)
Signed-off-by: Billy Yuan <billy112487983@gmail.com>
1 parent 1d28487 commit 961e670

File tree

7 files changed

+159
-6
lines changed

7 files changed

+159
-6
lines changed

vertx-mssql-client/src/main/asciidoc/index.adoc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ Currently the client supports the following SQL Server types
112112

113113
Tuple decoding uses the above types when storing values
114114

115+
=== Handling ENUM
116+
117+
SQL Server does not have ENUM data type but the client can map the retrieved string/numeric data type to enum.
118+
119+
You can encode Java enums as String like this:
120+
121+
[source,$lang]
122+
----
123+
{@link examples.MSSQLClientExamples#enumeratedType01Example}
124+
----
125+
126+
You can retrieve the ENUM column as Java enums like this:
127+
128+
[source,$lang]
129+
----
130+
{@link examples.MSSQLClientExamples#enumeratedType02Example}
131+
----
132+
115133
== Collector queries
116134

117135
You can use Java collectors with the query API:

vertx-mssql-client/src/main/java/examples/MSSQLClientExamples.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,30 @@ public void collector02Example(SqlClient client) {
214214
}
215215
});
216216
}
217+
218+
enum Color {
219+
red, green, blue
220+
}
221+
222+
public void enumeratedType01Example(SqlClient client) {
223+
client
224+
.preparedQuery("INSERT INTO colors VALUES (@p1)")
225+
.execute(Tuple.of(Color.red), res -> {
226+
// ...
227+
});
228+
}
229+
230+
public void enumeratedType02Example(SqlClient client) {
231+
client
232+
.preparedQuery("SELECT color FROM colors")
233+
.execute()
234+
.onComplete(res -> {
235+
if (res.succeeded()) {
236+
RowSet<Row> rows = res.result();
237+
for (Row row : rows) {
238+
System.out.println(row.get(Color.class, "color"));
239+
}
240+
}
241+
});
242+
}
217243
}

vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLRowImpl.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ public int getColumnIndex(String columnName) {
4444
return rowDesc.columnNames().indexOf(columnName);
4545
}
4646

47+
@Override
48+
public <T> T get(Class<T> type, int position) {
49+
if (type.isEnum()) {
50+
return type.cast(getEnum(type, position));
51+
} else {
52+
return super.get(type, position);
53+
}
54+
}
55+
4756
@Override
4857
public Buffer getBuffer(String columnName) {
4958
throw new UnsupportedOperationException();
@@ -148,4 +157,20 @@ public Buffer[] getBufferArray(String columnName) {
148157
public UUID[] getUUIDArray(String columnName) {
149158
throw new UnsupportedOperationException();
150159
}
160+
161+
private Object getEnum(Class enumType, int position) {
162+
Object val = getValue(position);
163+
if (val instanceof String) {
164+
return Enum.valueOf(enumType, (String) val);
165+
} else if (val instanceof Number) {
166+
int ordinal = ((Number) val).intValue();
167+
if (ordinal >= 0) {
168+
Object[] constants = enumType.getEnumConstants();
169+
if (ordinal < constants.length) {
170+
return constants[ordinal];
171+
}
172+
}
173+
}
174+
return null;
175+
}
151176
}

vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/codec/ExtendedQueryCommandCodec.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ private void encodeParamValue(ByteBuf payload, Object value) {
190190
encodeFloat8Parameter(payload, (Double) value);
191191
} else if (value instanceof String) {
192192
encodeNVarcharParameter(payload, (String) value);
193+
} else if (value instanceof Enum){
194+
encodeNVarcharParameter(payload, ((Enum<?>)value).name());
193195
} else if (value instanceof Boolean) {
194196
encodeBitNParameter(payload, (Boolean) value);
195197
} else if (value instanceof LocalDate) {

vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/codec/MSSQLDataTypeCodec.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ static String inferenceParamDefinitionByValueType(Object value) {
4747
} else if (value instanceof Numeric) {
4848
//TODO we may need some changes in Numeric to make this work
4949
throw new UnsupportedOperationException();
50+
} else if (value.getClass().isEnum()) {
51+
return parameterDefinitionsMapping.get(String.class);
5052
} else {
5153
String paramDefinition = parameterDefinitionsMapping.get(value.getClass());
5254
if (paramDefinition != null) {

vertx-mssql-client/src/test/java/io/vertx/mssqlclient/data/MSSQLDataTypeTestBase.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,38 +42,58 @@ protected <T> void testQueryDecodeGenericWithoutTable(TestContext ctx,
4242
String columnName,
4343
String type,
4444
String value,
45-
T expected) {
45+
Consumer<Row> checker) {
4646
MSSQLConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> {
4747
conn
4848
.query("SELECT CAST(" + value + " AS " + type + ") AS " + columnName)
4949
.execute(ctx.asyncAssertSuccess(result -> {
5050
ctx.assertEquals(1, result.size());
5151
Row row = result.iterator().next();
52-
ctx.assertEquals(expected, row.getValue(0));
53-
ctx.assertEquals(expected, row.getValue(columnName));
52+
checker.accept(row);
5453
conn.close();
5554
}));
5655
}));
5756
}
5857

58+
protected <T> void testQueryDecodeGenericWithoutTable(TestContext ctx,
59+
String columnName,
60+
String type,
61+
String value,
62+
T expected) {
63+
testQueryDecodeGenericWithoutTable(ctx, columnName, type, value, row -> {
64+
ctx.assertEquals(expected, row.getValue(0));
65+
ctx.assertEquals(expected, row.getValue(columnName));
66+
});
67+
}
68+
5969
protected <T> void testPreparedQueryDecodeGenericWithoutTable(TestContext ctx,
6070
String columnName,
6171
String type,
6272
String value,
63-
T expected) {
73+
Consumer<Row> checker) {
6474
MSSQLConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> {
6575
conn
6676
.preparedQuery("SELECT CAST(" + value + " AS " + type + ") AS " + columnName)
6777
.execute(ctx.asyncAssertSuccess(result -> {
6878
ctx.assertEquals(1, result.size());
6979
Row row = result.iterator().next();
70-
ctx.assertEquals(expected, row.getValue(0));
71-
ctx.assertEquals(expected, row.getValue(columnName));
80+
checker.accept(row);
7281
conn.close();
7382
}));
7483
}));
7584
}
7685

86+
protected <T> void testPreparedQueryDecodeGenericWithoutTable(TestContext ctx,
87+
String columnName,
88+
String type,
89+
String value,
90+
T expected) {
91+
testPreparedQueryDecodeGenericWithoutTable(ctx, columnName, type, value, row -> {
92+
ctx.assertEquals(expected, row.getValue(0));
93+
ctx.assertEquals(expected, row.getValue(columnName));
94+
});
95+
}
96+
7797
protected <T> void testQueryDecodeGeneric(TestContext ctx,
7898
String tableName,
7999
String columnName,
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2011-2020 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
12+
package io.vertx.mssqlclient.data;
13+
14+
import io.vertx.ext.unit.TestContext;
15+
import io.vertx.ext.unit.junit.VertxUnitRunner;
16+
import org.junit.Test;
17+
import org.junit.runner.RunWith;
18+
19+
@RunWith(VertxUnitRunner.class)
20+
public class MSSQLEnumDataTypeTest extends MSSQLDataTypeTestBase {
21+
@Test
22+
public void testQueryDecodeStringToJavaEnum(TestContext ctx) {
23+
testQueryDecodeGenericWithoutTable(ctx, "test_enum", "varchar", "'large'", row -> {
24+
ctx.assertEquals(Size.large, row.get(Size.class, 0));
25+
ctx.assertEquals(Size.large, row.get(Size.class, "test_enum"));
26+
ctx.assertEquals("large", row.get(String.class, 0));
27+
ctx.assertEquals("large", row.get(String.class, "test_enum"));
28+
ctx.assertEquals("large", row.getString(0));
29+
ctx.assertEquals("large", row.getString("test_enum"));
30+
});
31+
}
32+
33+
@Test
34+
public void testPreparedQueryDecodeStringToJavaEnum(TestContext ctx) {
35+
testPreparedQueryDecodeGenericWithoutTable(ctx, "test_enum", "varchar", "'large'", row -> {
36+
ctx.assertEquals(Size.large, row.get(Size.class, 0));
37+
ctx.assertEquals(Size.large, row.get(Size.class, "test_enum"));
38+
ctx.assertEquals("large", row.get(String.class, 0));
39+
ctx.assertEquals("large", row.get(String.class, "test_enum"));
40+
ctx.assertEquals("large", row.getString(0));
41+
ctx.assertEquals("large", row.getString("test_enum"));
42+
});
43+
}
44+
45+
@Test
46+
public void testPreparedQueryEncodeJavaEnumToString(TestContext ctx) {
47+
testPreparedQueryEncodeGeneric(ctx, "nullable_datatype", "test_varchar", Size.medium, row -> {
48+
ctx.assertEquals(Size.medium, row.get(Size.class, 0));
49+
ctx.assertEquals(Size.medium, row.get(Size.class, "test_varchar"));
50+
ctx.assertEquals("medium", row.get(String.class, 0));
51+
ctx.assertEquals("medium", row.get(String.class, "test_varchar"));
52+
ctx.assertEquals("medium", row.getString(0));
53+
ctx.assertEquals("medium", row.getString("test_varchar"));
54+
});
55+
}
56+
57+
private enum Size {
58+
x_small, small, medium, large, x_large;
59+
}
60+
}

0 commit comments

Comments
 (0)