Skip to content

Commit 602f8d7

Browse files
committed
PathCodec
1 parent 6af1108 commit 602f8d7

File tree

5 files changed

+244
-1
lines changed

5 files changed

+244
-1
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ public DefaultCodecs(ByteBufAllocator byteBufAllocator) {
100100
new PointCodec(byteBufAllocator),
101101
new BoxCodec(byteBufAllocator),
102102
new LineCodec(byteBufAllocator),
103-
new LsegCodec(byteBufAllocator)
103+
new LsegCodec(byteBufAllocator),
104+
new PathCodec(byteBufAllocator)
104105
));
105106
}
106107

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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 path} datatype in Postgres.
13+
*/
14+
public class Path {
15+
16+
private final List<Point> points;
17+
18+
private final boolean isOpen;
19+
20+
private Path(List<Point> points, boolean isOpen) {
21+
Assert.requireNonNull(points, "points must not be null");
22+
this.points = Collections.unmodifiableList(new ArrayList<>(points));
23+
this.isOpen = isOpen;
24+
}
25+
26+
public static Path of(boolean isOpen, List<Point> points) {
27+
return new Path(points, isOpen);
28+
}
29+
30+
public static Path of(boolean isOpen, Point... points) {
31+
return new Path(Arrays.asList(points), isOpen);
32+
}
33+
34+
public List<Point> getPoints() {
35+
return this.points;
36+
}
37+
38+
public boolean isOpen() {
39+
return this.isOpen;
40+
}
41+
42+
@Override
43+
public boolean equals(Object o) {
44+
if (this == o) {
45+
return true;
46+
}
47+
if (o == null || getClass() != o.getClass()) {
48+
return false;
49+
}
50+
Path path = (Path) o;
51+
return this.points.equals(path.points);
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Objects.hash(this.points);
57+
}
58+
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 PathCodec extends AbstractGeometryCodec<Path> {
11+
12+
PathCodec(ByteBufAllocator byteBufAllocator) {
13+
super(Path.class, PostgresqlObjectId.PATH, byteBufAllocator);
14+
}
15+
16+
@Override
17+
Path doDecodeBinary(ByteBuf byteBuffer) {
18+
boolean isOpen = byteBuffer.readBoolean();
19+
int size = byteBuffer.readInt();
20+
List<Point> points = new ArrayList<>();
21+
for (int i = 0; i < size; i++) {
22+
points.add(Point.of(byteBuffer.readDouble(), byteBuffer.readDouble()));
23+
}
24+
return Path.of(isOpen, points);
25+
}
26+
27+
@Override
28+
Path doDecodeText(String text) {
29+
boolean isOpen = text.startsWith("[");
30+
List<String> tokens = tokenizeTextData(text);
31+
List<Point> points = new ArrayList<>();
32+
for (int i = 0; i < tokens.size(); i += 2) {
33+
points.add(Point.of(Double.parseDouble(tokens.get(i)), Double.parseDouble(tokens.get(i + 1))));
34+
}
35+
return Path.of(isOpen, points);
36+
}
37+
38+
@Override
39+
ByteBuf doEncodeBinary(Path value) {
40+
List<Point> points = value.getPoints();
41+
ByteBuf buffer = this.byteBufAllocator
42+
.buffer(points.size() * 16 + 5)
43+
.writeBoolean(value.isOpen())
44+
.writeInt(points.size());
45+
points.forEach(point -> buffer.writeDouble(point.getX()).writeDouble(point.getY()));
46+
return buffer;
47+
}
48+
49+
}

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

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.r2dbc.postgresql.codec.Json;
2828
import io.r2dbc.postgresql.codec.Line;
2929
import io.r2dbc.postgresql.codec.Lseg;
30+
import io.r2dbc.postgresql.codec.Path;
3031
import io.r2dbc.postgresql.codec.Point;
3132
import io.r2dbc.spi.Blob;
3233
import io.r2dbc.spi.Clob;
@@ -481,6 +482,14 @@ void lseg() {
481482
testCodec(Lseg.class, Lseg.of(Point.of(1.11, 2.22), Point.of(3.33, 4.44)), "LSEG");
482483
}
483484

485+
@Test
486+
void path() {
487+
testCodec(Path.class, Path.of(false, Point.of(1.1, 2.2), Point.of(10.10, 10.10), Point.of(.42, 5.3)), "PATH");
488+
testCodec(Path.class, Path.of(true, Point.of(1.1, 2.2), Point.of(10.10, 10.10), Point.of(.42, 5.3)), "PATH");
489+
testCodec(Path.class, Path.of(false, Point.of(1.1, 2.2), Point.of(10.10, 10.10), Point.of(.42, 5.3), Point.of(-3.5, 0.)), "PATH");
490+
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");
491+
}
492+
484493
private static <T> Mono<T> close(Connection connection) {
485494
return Mono.from(connection
486495
.close())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package io.r2dbc.postgresql.codec;
2+
3+
import io.netty.buffer.ByteBuf;
4+
import io.r2dbc.postgresql.client.Parameter;
5+
import io.r2dbc.postgresql.client.ParameterAssert;
6+
import org.junit.jupiter.api.Test;
7+
8+
import static io.r2dbc.postgresql.client.Parameter.NULL_VALUE;
9+
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
10+
import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT;
11+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.LINE;
12+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.PATH;
13+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.POINT;
14+
import static io.r2dbc.postgresql.util.ByteBufUtils.encode;
15+
import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST;
16+
import static org.assertj.core.api.Assertions.assertThat;
17+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
18+
19+
/**
20+
* Unit tests for {@link PathCodec}.
21+
*/
22+
public class PathCodecUnitTest {
23+
24+
private static final int dataType = PATH.getObjectId();
25+
26+
@Test
27+
void constructorNoByteBufAllocator() {
28+
assertThatIllegalArgumentException().isThrownBy(() -> new PathCodec(null))
29+
.withMessage("byteBufAllocator must not be null");
30+
}
31+
32+
@Test
33+
void decode() {
34+
Path closedPath = Path.of(false, Point.of(-10.42, 3.14), Point.of(10.42, -3.14));
35+
Path openPath = Path.of(true, Point.of(-10.42, 3.14), Point.of(10.42, -3.14));
36+
37+
assertThat(new PathCodec(TEST).decode(encode(TEST, "((-10.42,3.14),(10.42,-3.14))"), dataType, FORMAT_TEXT, Path.class)).isEqualTo(closedPath);
38+
assertThat(new PathCodec(TEST).decode(encode(TEST, "[(-10.42,3.14),(10.42,-3.14)]"), dataType, FORMAT_TEXT, Path.class)).isEqualTo(openPath);
39+
40+
ByteBuf closedPathByteFormat = TEST.buffer(37)
41+
.writeBoolean(false)
42+
.writeInt(2)
43+
.writeDouble(-10.42)
44+
.writeDouble(3.14)
45+
.writeDouble(10.42)
46+
.writeDouble(-3.14);
47+
assertThat(new PathCodec(TEST).decode(closedPathByteFormat, dataType, FORMAT_BINARY, Path.class)).isEqualTo(closedPath);
48+
ByteBuf openPathByteFormat = TEST.buffer(37)
49+
.writeBoolean(true)
50+
.writeInt(2)
51+
.writeDouble(-10.42)
52+
.writeDouble(3.14)
53+
.writeDouble(10.42)
54+
.writeDouble(-3.14);
55+
assertThat(new PathCodec(TEST).decode(openPathByteFormat, dataType, FORMAT_BINARY, Path.class)).isEqualTo(openPath);
56+
}
57+
58+
@Test
59+
void decodeNoByteBuf() {
60+
assertThat(new PathCodec(TEST).decode(null, dataType, FORMAT_TEXT, Path.class)).isNull();
61+
}
62+
63+
@Test
64+
void doCanDecode() {
65+
PathCodec codec = new PathCodec(TEST);
66+
assertThat(codec.doCanDecode(PATH, FORMAT_BINARY)).isTrue();
67+
assertThat(codec.doCanDecode(PATH, FORMAT_TEXT)).isTrue();
68+
assertThat(codec.doCanDecode(LINE, FORMAT_TEXT)).isFalse();
69+
assertThat(codec.doCanDecode(POINT, FORMAT_TEXT)).isFalse();
70+
}
71+
72+
@Test
73+
void doCanDecodeNoFormat() {
74+
assertThatIllegalArgumentException().isThrownBy(() -> new PathCodec(TEST).doCanDecode(PATH, null))
75+
.withMessage("format must not be null");
76+
}
77+
78+
@Test
79+
void doCanDecodeNoType() {
80+
assertThatIllegalArgumentException().isThrownBy(() -> new PathCodec(TEST).doCanDecode(null, FORMAT_TEXT))
81+
.withMessage("type must not be null");
82+
}
83+
84+
@Test
85+
void doEncode() {
86+
Path closedPath = Path.of(false, Point.of(-10.42, 3.14), Point.of(10.42, -3.14));
87+
ParameterAssert.assertThat(new PathCodec(TEST).doEncode(closedPath))
88+
.hasFormat(FORMAT_BINARY)
89+
.hasType(dataType)
90+
.hasValue(TEST.buffer(37)
91+
.writeBoolean(false)
92+
.writeInt(2)
93+
.writeDouble(-10.42)
94+
.writeDouble(3.14)
95+
.writeDouble(10.42)
96+
.writeDouble(-3.14)
97+
);
98+
99+
Path openPath = Path.of(true, Point.of(-10.42, 3.14), Point.of(10.42, -3.14));
100+
ParameterAssert.assertThat(new PathCodec(TEST).doEncode(openPath))
101+
.hasFormat(FORMAT_BINARY)
102+
.hasType(dataType)
103+
.hasValue(TEST.buffer(37)
104+
.writeBoolean(true)
105+
.writeInt(2)
106+
.writeDouble(-10.42)
107+
.writeDouble(3.14)
108+
.writeDouble(10.42)
109+
.writeDouble(-3.14)
110+
);
111+
}
112+
113+
@Test
114+
void doEncodeNoValue() {
115+
assertThatIllegalArgumentException().isThrownBy(() -> new PathCodec(TEST).doEncode(null))
116+
.withMessage("value must not be null");
117+
}
118+
119+
@Test
120+
void encodeNull() {
121+
ParameterAssert.assertThat(new PathCodec(TEST).encodeNull())
122+
.isEqualTo(new Parameter(FORMAT_BINARY, dataType, NULL_VALUE));
123+
}
124+
125+
}

0 commit comments

Comments
 (0)