Skip to content

Commit 401477f

Browse files
committed
feature: adding support for circle type
1 parent a020155 commit 401477f

File tree

6 files changed

+298
-0
lines changed

6 files changed

+298
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.r2dbc.postgresql.codec;
18+
19+
public final class Circle {
20+
private final Point center;
21+
private final double radius;
22+
23+
public Circle(Point center, double radius) {
24+
this.center = center;
25+
this.radius = radius;
26+
}
27+
28+
public Circle(double x, double y, double r) {
29+
this(Point.of(x, y), r);
30+
}
31+
32+
public Point getCenter() {
33+
return this.center;
34+
}
35+
36+
public double getRadius() {
37+
return this.radius;
38+
}
39+
40+
/**
41+
* @param obj Object to compare with
42+
* @return true if the two circles are identical
43+
*/
44+
@Override
45+
public boolean equals(Object obj) {
46+
if (obj instanceof Circle) {
47+
Circle circle = (Circle) obj;
48+
return circle.center.equals(center) && circle.radius == radius;
49+
}
50+
return false;
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
long v = Double.doubleToLongBits(radius);
56+
return (int) (center.hashCode() ^ v ^ (v >>> 32));
57+
}
58+
59+
@Override
60+
public String toString() {
61+
return "<" + center.toString() + "," + radius + ">";
62+
}
63+
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.r2dbc.postgresql.codec;
18+
19+
import io.netty.buffer.ByteBuf;
20+
import io.netty.buffer.ByteBufAllocator;
21+
import io.r2dbc.postgresql.client.Parameter;
22+
import io.r2dbc.postgresql.message.Format;
23+
import io.r2dbc.postgresql.type.PostgresqlObjectId;
24+
import io.r2dbc.postgresql.util.Assert;
25+
import io.r2dbc.postgresql.util.ByteBufUtils;
26+
27+
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
28+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.CIRCLE;
29+
30+
final class CircleCodec extends AbstractCodec<Circle> {
31+
32+
private final ByteBufAllocator byteBufAllocator;
33+
34+
CircleCodec(ByteBufAllocator byteBufAllocator) {
35+
super(Circle.class);
36+
this.byteBufAllocator = Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
37+
}
38+
39+
@Override
40+
boolean doCanDecode(PostgresqlObjectId type, Format format) {
41+
Assert.requireNonNull(type, "type must not be null");
42+
43+
return CIRCLE == type;
44+
}
45+
46+
@Override
47+
Circle doDecode(ByteBuf buffer, PostgresqlObjectId dataType, Format format, Class<? extends Circle> type) {
48+
Assert.requireNonNull(buffer, "byteBuf must not be null");
49+
Assert.requireNonNull(type, "type must not be null");
50+
Assert.requireNonNull(format, "format must not be null");
51+
52+
if (format == FORMAT_BINARY) {
53+
double x = buffer.readDouble();
54+
double y = buffer.readDouble();
55+
double r = buffer.readDouble();
56+
return new Circle(Point.of(x, y), r);
57+
}
58+
59+
String decodedAsString = ByteBufUtils.decode(buffer);
60+
String parenRemovedVal = decodedAsString.replaceAll("[()<>]", "");
61+
String[] coordinatesAsString = parenRemovedVal.split(",");
62+
double x = Double.parseDouble(coordinatesAsString[0]);
63+
double y = Double.parseDouble(coordinatesAsString[1]);
64+
double r = Double.parseDouble(coordinatesAsString[2]);
65+
return new Circle(Point.of(x, y), r);
66+
}
67+
68+
/**
69+
* @param value the {@code value}.
70+
* @return Circle in string format as understood by Postgresql - &lt(x,y),r&gt
71+
*/
72+
@Override
73+
Parameter doEncode(Circle value) {
74+
Assert.requireNonNull(value, "value must not be null");
75+
Point center = value.getCenter();
76+
return create(CIRCLE, FORMAT_BINARY, () -> this.byteBufAllocator.buffer(lengthInBytes())
77+
.writeDouble(center.getX())
78+
.writeDouble(center.getY())
79+
.writeDouble(value.getRadius()));
80+
}
81+
82+
@Override
83+
public Parameter encodeNull() {
84+
return createNull(CIRCLE, FORMAT_BINARY);
85+
}
86+
87+
int lengthInBytes() {
88+
return 24;
89+
}
90+
91+
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ public DefaultCodecs(ByteBufAllocator byteBufAllocator) {
9595
new IntegerArrayCodec(byteBufAllocator),
9696
new LongArrayCodec(byteBufAllocator),
9797

98+
//Geometry
99+
new CircleCodec(byteBufAllocator),
98100
new PointCodec(byteBufAllocator)
99101
));
100102
}

src/main/java/io/r2dbc/postgresql/type/PostgresqlObjectId.java

+25
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ public enum PostgresqlObjectId {
7777
*/
7878
CHAR_ARRAY(1002),
7979

80+
/**
81+
* The circle object id
82+
*/
83+
CIRCLE(718),
84+
8085
/**
8186
* The date object id.
8287
*/
@@ -177,6 +182,16 @@ public enum PostgresqlObjectId {
177182
*/
178183
JSONB_ARRAY(3807),
179184

185+
/**
186+
* The line object id
187+
*/
188+
LINE(628),
189+
190+
/**
191+
* The line segment object id
192+
*/
193+
LINE_SEGMENT(601),
194+
180195
/**
181196
* The money object id.
182197
*/
@@ -217,6 +232,11 @@ public enum PostgresqlObjectId {
217232
*/
218233
OID_ARRAY(1028),
219234

235+
/**
236+
* the path object id
237+
*/
238+
PATH(602),
239+
220240
/**
221241
* The point object id.
222242
*/
@@ -227,6 +247,11 @@ public enum PostgresqlObjectId {
227247
*/
228248
POINT_ARRAY(1017),
229249

250+
/**
251+
* the polygon object id
252+
*/
253+
POLYGON(604),
254+
230255
/**
231256
* The ref cursor object id.
232257
*/

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

+7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.netty.buffer.Unpooled;
2222
import io.r2dbc.postgresql.api.PostgresqlResult;
2323
import io.r2dbc.postgresql.api.PostgresqlStatement;
24+
import io.r2dbc.postgresql.codec.Circle;
2425
import io.r2dbc.postgresql.codec.EnumCodec;
2526
import io.r2dbc.postgresql.codec.Json;
2627
import io.r2dbc.postgresql.codec.Point;
@@ -171,6 +172,12 @@ public Publisher<ByteBuffer> stream() {
171172
testCodec(Blob.class, byteToBlob.apply(new byte[]{}), equality, "BYTEA");
172173
}
173174

175+
@Test
176+
void circle() {
177+
testCodec(Circle.class, new Circle(Point.of(1.12, 2.12), 3.12), "CIRCLE");
178+
testCodec(Circle.class, new Circle(Point.of(Double.MIN_VALUE, Double.MIN_VALUE), Double.MAX_VALUE), "CIRCLE");
179+
}
180+
174181
@Test
175182
void clob() {
176183
testCodec(Clob.class,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2017-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.r2dbc.postgresql.codec;
18+
19+
import io.netty.buffer.ByteBuf;
20+
import io.r2dbc.postgresql.client.Parameter;
21+
import io.r2dbc.postgresql.client.ParameterAssert;
22+
import org.junit.jupiter.api.Test;
23+
24+
import static io.r2dbc.postgresql.client.Parameter.NULL_VALUE;
25+
import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
26+
import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT;
27+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.CIRCLE;
28+
import static io.r2dbc.postgresql.type.PostgresqlObjectId.VARCHAR;
29+
import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST;
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
32+
33+
/**
34+
* Unit tests for {@link CircleCodec}.
35+
*/
36+
final class CircleCodecUnitTests {
37+
38+
@Test
39+
void constructorNoByteBufAllocator() {
40+
assertThatIllegalArgumentException().isThrownBy(() -> new CircleCodec(null))
41+
.withMessage("byteBufAllocator must not be null");
42+
}
43+
44+
@Test
45+
void doCanDecodeNoType() {
46+
assertThatIllegalArgumentException().isThrownBy(() -> new CircleCodec(TEST).doCanDecode(null, FORMAT_BINARY))
47+
.withMessage("type must not be null");
48+
}
49+
50+
@Test
51+
void doCanDecode() {
52+
CircleCodec codec = new CircleCodec(TEST);
53+
54+
assertThat(codec.doCanDecode(VARCHAR, FORMAT_BINARY)).isFalse();
55+
assertThat(codec.doCanDecode(CIRCLE, FORMAT_TEXT)).isTrue();
56+
assertThat(codec.doCanDecode(CIRCLE, FORMAT_BINARY)).isTrue();
57+
}
58+
59+
@Test
60+
void doDecodeNoByteBuf() {
61+
assertThatIllegalArgumentException().isThrownBy(() -> new CircleCodec(TEST).doDecode(null, CIRCLE, FORMAT_BINARY, Circle.class))
62+
.withMessage("byteBuf must not be null");
63+
}
64+
65+
@Test
66+
void doDecodeNoType() {
67+
assertThatIllegalArgumentException().isThrownBy(() -> new CircleCodec(TEST).doDecode(TEST.buffer(), CIRCLE, FORMAT_BINARY, null))
68+
.withMessage("type must not be null");
69+
}
70+
71+
@Test
72+
void doDecodeNoFormat() {
73+
assertThatIllegalArgumentException().isThrownBy(() -> new CircleCodec(TEST).doDecode(TEST.buffer(), CIRCLE, null, Circle.class))
74+
.withMessage("format must not be null");
75+
}
76+
77+
@Test
78+
void doDecode() {
79+
CircleCodec codec = new CircleCodec(TEST);
80+
Point point = Point.of(1.12, 2.12);
81+
Circle circle = new Circle(point, 3.12);
82+
ByteBuf circleAsBinary = TEST.buffer(codec.lengthInBytes()).writeDouble(1.12).writeDouble(2.12).writeDouble(3.12);
83+
assertThat(codec.doDecode(circleAsBinary, CIRCLE, FORMAT_BINARY, Circle.class)).isEqualTo(circle);
84+
}
85+
86+
@Test
87+
void doEncodeNoValue() {
88+
assertThatIllegalArgumentException().isThrownBy(() -> new CircleCodec(TEST).doEncode(null))
89+
.withMessage("value must not be null");
90+
}
91+
92+
@Test
93+
void doEncode() {
94+
CircleCodec codec = new CircleCodec(TEST);
95+
ByteBuf circleAsBinary = TEST.buffer(codec.lengthInBytes()).writeDouble(1.12).writeDouble(2.12).writeDouble(3.12);
96+
97+
ParameterAssert.assertThat(codec.doEncode(new Circle(Point.of(1.12, 2.12), 3.12)))
98+
.hasFormat(FORMAT_BINARY)
99+
.hasType(CIRCLE.getObjectId())
100+
.hasValue(circleAsBinary);
101+
}
102+
103+
@Test
104+
void encodeNull() {
105+
ParameterAssert.assertThat(new CircleCodec(TEST).encodeNull())
106+
.isEqualTo(new Parameter(FORMAT_BINARY, CIRCLE.getObjectId(), NULL_VALUE));
107+
}
108+
109+
}

0 commit comments

Comments
 (0)