Skip to content

Commit 6d5c22d

Browse files
committed
PolygonCodec
1 parent 602f8d7 commit 6d5c22d

File tree

5 files changed

+197
-1
lines changed

5 files changed

+197
-1
lines changed

src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ public DefaultCodecs(ByteBufAllocator byteBufAllocator) {
101101
new BoxCodec(byteBufAllocator),
102102
new LineCodec(byteBufAllocator),
103103
new LsegCodec(byteBufAllocator),
104-
new PathCodec(byteBufAllocator)
104+
new PathCodec(byteBufAllocator),
105+
new PolygonCodec(byteBufAllocator)
105106
));
106107
}
107108

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package io.r2dbc.postgresql.codec;
2+
3+
import io.r2dbc.postgresql.util.Assert;
4+
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.Collections;
8+
import java.util.List;
9+
import java.util.Objects;
10+
11+
/**
12+
* Value object that maps to the {@code polygon} datatype in Postgres.
13+
*/
14+
public final class Polygon {
15+
16+
private final List<Point> points;
17+
18+
private Polygon(List<Point> points) {
19+
Assert.requireNonNull(points, "points must not be null");
20+
this.points = Collections.unmodifiableList(new ArrayList<>(points));
21+
}
22+
23+
public static Polygon of(List<Point> points) {
24+
return new Polygon(points);
25+
}
26+
27+
public static Polygon of(Point... points) {
28+
return new Polygon(Arrays.asList(points));
29+
}
30+
31+
public List<Point> getPoints() {
32+
return this.points;
33+
}
34+
35+
@Override
36+
public boolean equals(Object o) {
37+
if (this == o) {
38+
return true;
39+
}
40+
if (o == null || getClass() != o.getClass()) {
41+
return false;
42+
}
43+
Polygon polygon = (Polygon) o;
44+
return this.points.equals(polygon.points);
45+
}
46+
47+
@Override
48+
public int hashCode() {
49+
return Objects.hash(this.points);
50+
}
51+
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package io.r2dbc.postgresql.codec;
2+
3+
import io.netty.buffer.ByteBuf;
4+
import io.netty.buffer.ByteBufAllocator;
5+
import io.r2dbc.postgresql.type.PostgresqlObjectId;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
final class PolygonCodec extends AbstractGeometryCodec<Polygon> {
11+
12+
PolygonCodec(ByteBufAllocator byteBufAllocator) {
13+
super(Polygon.class, PostgresqlObjectId.POLYGON, byteBufAllocator);
14+
}
15+
16+
@Override
17+
Polygon doDecodeBinary(ByteBuf byteBuffer) {
18+
int size = byteBuffer.readInt();
19+
List<Point> points = new ArrayList<>();
20+
for (int i = 0; i < size; i++) {
21+
points.add(Point.of(byteBuffer.readDouble(), byteBuffer.readDouble()));
22+
}
23+
return Polygon.of(points);
24+
}
25+
26+
@Override
27+
Polygon doDecodeText(String text) {
28+
List<String> tokens = tokenizeTextData(text);
29+
List<Point> points = new ArrayList<>();
30+
for (int i = 0; i < tokens.size(); i += 2) {
31+
points.add(Point.of(Double.parseDouble(tokens.get(i)), Double.parseDouble(tokens.get(i + 1))));
32+
}
33+
return Polygon.of(points);
34+
}
35+
36+
@Override
37+
ByteBuf doEncodeBinary(Polygon value) {
38+
List<Point> points = value.getPoints();
39+
ByteBuf buffer = this.byteBufAllocator
40+
.buffer(points.size() * 16 + 4)
41+
.writeInt(points.size());
42+
points.forEach(point -> buffer.writeDouble(point.getX()).writeDouble(point.getY()));
43+
return buffer;
44+
}
45+
46+
}

src/test/java/io/r2dbc/postgresql/AbstractCodecIntegrationTests.java

+7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io.r2dbc.postgresql.codec.Lseg;
3030
import io.r2dbc.postgresql.codec.Path;
3131
import io.r2dbc.postgresql.codec.Point;
32+
import io.r2dbc.postgresql.codec.Polygon;
3233
import io.r2dbc.spi.Blob;
3334
import io.r2dbc.spi.Clob;
3435
import io.r2dbc.spi.Connection;
@@ -490,6 +491,12 @@ void path() {
490491
testCodec(Path.class, Path.of(true, Point.of(1.1, 2.2), Point.of(10.10, 10.10), Point.of(.42, 5.3), Point.of(-3.5, 0.)), "PATH");
491492
}
492493

494+
@Test
495+
void polygon() {
496+
testCodec(Polygon.class, Polygon.of(Point.of(1.1, 2.2), Point.of(10.10, 10.10), Point.of(.42, 5.3)), "POLYGON");
497+
testCodec(Polygon.class, Polygon.of(Point.of(1.1, 2.2), Point.of(10.10, 10.10), Point.of(.42, 5.3), Point.of(-3.5, 0.)), "POLYGON");;
498+
}
499+
493500
private static <T> Mono<T> close(Connection connection) {
494501
return Mono.from(connection
495502
.close())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package io.r2dbc.postgresql.codec;
2+
3+
import io.r2dbc.postgresql.client.Parameter;
4+
import io.r2dbc.postgresql.client.ParameterAssert;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static io.r2dbc.postgresql.client.Parameter.NULL_VALUE;
8+
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
9+
import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT;
10+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.LINE;
11+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.PATH;
12+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.POLYGON;
13+
import static io.r2dbc.postgresql.util.ByteBufUtils.encode;
14+
import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST;
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
17+
18+
/**
19+
* Unit tests for {@link PolygonCodec}.
20+
*/
21+
public class PolygonCodecUnitTest {
22+
23+
private static final int dataType = POLYGON.getObjectId();
24+
25+
@Test
26+
void constructorNoByteBufAllocator() {
27+
assertThatIllegalArgumentException().isThrownBy(() -> new PolygonCodec(null))
28+
.withMessage("byteBufAllocator must not be null");
29+
}
30+
31+
@Test
32+
void decode() {
33+
Polygon polygon = Polygon.of(Point.of(-10.42, 3.14), Point.of(10.42, -3.14));
34+
35+
assertThat(new PolygonCodec(TEST).decode(encode(TEST, "((-10.42,3.14),(10.42,-3.14))"), dataType, FORMAT_TEXT, Polygon.class)).isEqualTo(polygon);
36+
}
37+
38+
@Test
39+
void decodeNoByteBuf() {
40+
assertThat(new PolygonCodec(TEST).decode(null, dataType, FORMAT_TEXT, Polygon.class)).isNull();
41+
}
42+
43+
@Test
44+
void doCanDecode() {
45+
PolygonCodec codec = new PolygonCodec(TEST);
46+
assertThat(codec.doCanDecode(POLYGON, FORMAT_BINARY)).isTrue();
47+
assertThat(codec.doCanDecode(LINE, FORMAT_TEXT)).isFalse();
48+
assertThat(codec.doCanDecode(PATH, FORMAT_TEXT)).isFalse();
49+
}
50+
51+
@Test
52+
void doCanDecodeNoFormat() {
53+
assertThatIllegalArgumentException().isThrownBy(() -> new PolygonCodec(TEST).doCanDecode(PATH, null))
54+
.withMessage("format must not be null");
55+
}
56+
57+
@Test
58+
void doCanDecodeNoType() {
59+
assertThatIllegalArgumentException().isThrownBy(() -> new PolygonCodec(TEST).doCanDecode(null, FORMAT_TEXT))
60+
.withMessage("type must not be null");
61+
}
62+
63+
@Test
64+
void doEncode() {
65+
Polygon polygon = Polygon.of(Point.of(-10.42, 3.14), Point.of(10.42, -3.14));
66+
ParameterAssert.assertThat(new PolygonCodec(TEST).doEncode(polygon))
67+
.hasFormat(FORMAT_BINARY)
68+
.hasType(dataType)
69+
.hasValue(TEST.buffer(37)
70+
.writeInt(2)
71+
.writeDouble(-10.42)
72+
.writeDouble(3.14)
73+
.writeDouble(10.42)
74+
.writeDouble(-3.14)
75+
);
76+
}
77+
78+
@Test
79+
void doEncodeNoValue() {
80+
assertThatIllegalArgumentException().isThrownBy(() -> new PolygonCodec(TEST).doEncode(null))
81+
.withMessage("value must not be null");
82+
}
83+
84+
@Test
85+
void encodeNull() {
86+
ParameterAssert.assertThat(new PolygonCodec(TEST).encodeNull())
87+
.isEqualTo(new Parameter(FORMAT_BINARY, dataType, NULL_VALUE));
88+
}
89+
90+
}

0 commit comments

Comments
 (0)