From af5e7706ad0182ef408dae8b1cc4c559791c492a Mon Sep 17 00:00:00 2001 From: steverigney Date: Sun, 27 Aug 2023 14:30:25 +0100 Subject: [PATCH 1/3] adding codecs for multiple java 8 data types - gh-591 --- .../postgresql/codec/DayOfWeekCodec.java | 28 +++ .../r2dbc/postgresql/codec/DefaultCodecs.java | 232 +++++++++--------- .../codec/IntegerCodecDelegate.java | 73 ++++++ .../io/r2dbc/postgresql/codec/MonthCodec.java | 28 +++ .../r2dbc/postgresql/codec/MonthDayCodec.java | 28 +++ .../r2dbc/postgresql/codec/PeriodCodec.java | 28 +++ .../io/r2dbc/postgresql/codec/YearCodec.java | 28 +++ .../postgresql/codec/YearMonthCodec.java | 28 +++ .../r2dbc-postgresql/reflect-config.json | 12 + .../AbstractCodecIntegrationTests.java | 60 ++--- .../postgresql/codec/DayOfWeekCodecTest.java | 108 ++++++++ .../postgresql/codec/MonthCodecTest.java | 109 ++++++++ .../postgresql/codec/MonthDayCodecTest.java | 98 ++++++++ .../postgresql/codec/PeriodCodecTest.java | 129 ++++++++++ .../r2dbc/postgresql/codec/YearCodecTest.java | 112 +++++++++ .../postgresql/codec/YearMonthCodecTest.java | 98 ++++++++ 16 files changed, 1056 insertions(+), 143 deletions(-) create mode 100644 src/main/java/io/r2dbc/postgresql/codec/DayOfWeekCodec.java create mode 100644 src/main/java/io/r2dbc/postgresql/codec/IntegerCodecDelegate.java create mode 100644 src/main/java/io/r2dbc/postgresql/codec/MonthCodec.java create mode 100644 src/main/java/io/r2dbc/postgresql/codec/MonthDayCodec.java create mode 100644 src/main/java/io/r2dbc/postgresql/codec/PeriodCodec.java create mode 100644 src/main/java/io/r2dbc/postgresql/codec/YearCodec.java create mode 100644 src/main/java/io/r2dbc/postgresql/codec/YearMonthCodec.java create mode 100644 src/test/java/io/r2dbc/postgresql/codec/DayOfWeekCodecTest.java create mode 100644 src/test/java/io/r2dbc/postgresql/codec/MonthCodecTest.java create mode 100644 src/test/java/io/r2dbc/postgresql/codec/MonthDayCodecTest.java create mode 100644 src/test/java/io/r2dbc/postgresql/codec/PeriodCodecTest.java create mode 100644 src/test/java/io/r2dbc/postgresql/codec/YearCodecTest.java create mode 100644 src/test/java/io/r2dbc/postgresql/codec/YearMonthCodecTest.java diff --git a/src/main/java/io/r2dbc/postgresql/codec/DayOfWeekCodec.java b/src/main/java/io/r2dbc/postgresql/codec/DayOfWeekCodec.java new file mode 100644 index 00000000..a6f47fb1 --- /dev/null +++ b/src/main/java/io/r2dbc/postgresql/codec/DayOfWeekCodec.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBufAllocator; + +import java.time.DayOfWeek; + +final class DayOfWeekCodec extends IntegerCodecDelegate { + + DayOfWeekCodec(ByteBufAllocator byteBufAllocator) { + super(DayOfWeek.class, byteBufAllocator, DayOfWeek::getValue, DayOfWeek::of); + } +} diff --git a/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java b/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java index 5e5d9473..16e24074 100644 --- a/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java +++ b/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java @@ -44,10 +44,10 @@ */ public final class DefaultCodecs implements Codecs, CodecRegistry { - private final List> codecs; - private final CodecLookup codecLookup; + private final List> codecs; + /** * Create a new instance of {@link DefaultCodecs} preferring detached (copied buffers). * @@ -96,97 +96,6 @@ public DefaultCodecs(ByteBufAllocator byteBufAllocator, boolean preferAttachedBu this.codecLookup.afterCodecAdded(); } - @SuppressWarnings({"unchecked", "rawtypes"}) - private static List> getDefaultCodecs(ByteBufAllocator byteBufAllocator, boolean preferAttachedBuffers, CodecConfiguration configuration) { - - List> codecs = new CopyOnWriteArrayList<>(Arrays.asList( - - // Prioritized Codecs - new StringCodec(byteBufAllocator), - new InstantCodec(byteBufAllocator, configuration::getZoneId), - new ZonedDateTimeCodec(byteBufAllocator), - new BinaryByteBufferCodec(byteBufAllocator), - new BinaryByteArrayCodec(byteBufAllocator), - - new BigDecimalCodec(byteBufAllocator), - new BigIntegerCodec(byteBufAllocator), - new BooleanCodec(byteBufAllocator), - new CharacterCodec(byteBufAllocator), - new DoubleCodec(byteBufAllocator), - new FloatCodec(byteBufAllocator), - new InetAddressCodec(byteBufAllocator), - new IntegerCodec(byteBufAllocator), - new IntervalCodec(byteBufAllocator), - new LocalDateCodec(byteBufAllocator), - new LocalDateTimeCodec(byteBufAllocator, configuration::getZoneId), - new LocalTimeCodec(byteBufAllocator), - new LongCodec(byteBufAllocator), - new OffsetDateTimeCodec(byteBufAllocator), - new OffsetTimeCodec(byteBufAllocator), - new ShortCodec(byteBufAllocator), - new UriCodec(byteBufAllocator), - new UrlCodec(byteBufAllocator), - new UuidCodec(byteBufAllocator), - new ZoneIdCodec(byteBufAllocator), - - // JSON - new JsonCodec(byteBufAllocator, preferAttachedBuffers), - new JsonByteArrayCodec(byteBufAllocator), - new JsonByteBufCodec(byteBufAllocator), - new JsonByteBufferCodec(byteBufAllocator), - new JsonInputStreamCodec(byteBufAllocator), - new JsonStringCodec(byteBufAllocator), - - // Fallback for Object.class - new ByteCodec(byteBufAllocator), - new DateCodec(byteBufAllocator, configuration::getZoneId), - - new BlobCodec(byteBufAllocator), - new ClobCodec(byteBufAllocator), - RefCursorCodec.INSTANCE, - RefCursorNameCodec.INSTANCE, - - // Array - new StringArrayCodec(byteBufAllocator), - - // Geometry - new CircleCodec(byteBufAllocator), - new PointCodec(byteBufAllocator), - new BoxCodec(byteBufAllocator), - new LineCodec(byteBufAllocator), - new LsegCodec(byteBufAllocator), - new PathCodec(byteBufAllocator), - new PolygonCodec(byteBufAllocator) - )); - - List> defaultArrayCodecs = new ArrayList<>(); - - for (Codec codec : codecs) { - - if (codec instanceof ArrayCodecDelegate) { - - Assert.requireType(codec, AbstractCodec.class, "Codec " + codec + " must be a subclass of AbstractCodec to be registered as generic array codec"); - ArrayCodecDelegate delegate = (ArrayCodecDelegate) codec; - Class componentType = delegate.type(); - - if (codec instanceof BoxCodec) { - // BOX[] uses a ';' as a delimiter (i.e. "{(3.7,4.6),(1.9,2.8);(5,7),(1.5,3.3)}") - defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate.getArrayDataType(), delegate, componentType, (byte) ';')); - } else if (codec instanceof AbstractNumericCodec) { - defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.NUMERIC_ARRAY_TYPES)); - } else if (codec instanceof AbstractTemporalCodec) { - defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.DATE_ARRAY_TYPES)); - } else { - defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate, componentType)); - } - } - } - - codecs.addAll(defaultArrayCodecs); - - return codecs; - } - @Override public void addFirst(Codec codec) { Assert.requireNonNull(codec, "codec must not be null"); @@ -264,6 +173,35 @@ public EncodedParameter encode(Object value) { return encodeParameterValue(value, dataType, parameterValue); } + @Override + public EncodedParameter encodeNull(Class type) { + Assert.requireNonNull(type, "type must not be null"); + + Codec codec = this.codecLookup.findEncodeNullCodec(type); + if (codec != null) { + return codec.encodeNull(); + } + + throw new IllegalArgumentException(String.format("Cannot encode null parameter of type %s", type.getName())); + } + + @Override + public Iterator> iterator() { + return Collections.unmodifiableList(new ArrayList<>(this.codecs)).iterator(); + } + + @Override + public Class preferredType(int dataType, Format format) { + Assert.requireNonNull(format, "format must not be null"); + + Codec codec = this.codecLookup.findDecodeCodec(dataType, format, Object.class); + if (codec instanceof CodecMetadata) { + return ((CodecMetadata) codec).type(); + } + + return null; + } + EncodedParameter encodeParameterValue(Object value, @Nullable PostgresTypeIdentifier dataType, @Nullable Object parameterValue) { if (dataType == null) { @@ -290,33 +228,101 @@ EncodedParameter encodeParameterValue(Object value, @Nullable PostgresTypeIdenti throw new IllegalArgumentException(String.format("Cannot encode parameter of type %s (%s)", value.getClass().getName(), parameterValue)); } - @Override - public EncodedParameter encodeNull(Class type) { - Assert.requireNonNull(type, "type must not be null"); + @SuppressWarnings({"unchecked", "rawtypes"}) + private static List> getDefaultCodecs(ByteBufAllocator byteBufAllocator, boolean preferAttachedBuffers, CodecConfiguration configuration) { - Codec codec = this.codecLookup.findEncodeNullCodec(type); - if (codec != null) { - return codec.encodeNull(); - } + List> codecs = new CopyOnWriteArrayList<>(Arrays.asList( - throw new IllegalArgumentException(String.format("Cannot encode null parameter of type %s", type.getName())); - } + // Prioritized Codecs + new StringCodec(byteBufAllocator), + new InstantCodec(byteBufAllocator, configuration::getZoneId), + new ZonedDateTimeCodec(byteBufAllocator), + new BinaryByteBufferCodec(byteBufAllocator), + new BinaryByteArrayCodec(byteBufAllocator), - @Override - public Class preferredType(int dataType, Format format) { - Assert.requireNonNull(format, "format must not be null"); + new BigDecimalCodec(byteBufAllocator), + new BigIntegerCodec(byteBufAllocator), + new BooleanCodec(byteBufAllocator), + new CharacterCodec(byteBufAllocator), + new DoubleCodec(byteBufAllocator), + new FloatCodec(byteBufAllocator), + new InetAddressCodec(byteBufAllocator), + new IntegerCodec(byteBufAllocator), + new IntervalCodec(byteBufAllocator), + new LocalDateCodec(byteBufAllocator), + new LocalDateTimeCodec(byteBufAllocator, configuration::getZoneId), + new LocalTimeCodec(byteBufAllocator), + new LongCodec(byteBufAllocator), + new OffsetDateTimeCodec(byteBufAllocator), + new OffsetTimeCodec(byteBufAllocator), + new ShortCodec(byteBufAllocator), + new UriCodec(byteBufAllocator), + new UrlCodec(byteBufAllocator), + new UuidCodec(byteBufAllocator), + new ZoneIdCodec(byteBufAllocator), + new DayOfWeekCodec(byteBufAllocator), + new MonthCodec(byteBufAllocator), + new MonthDayCodec(byteBufAllocator), + new PeriodCodec(byteBufAllocator), + new YearCodec(byteBufAllocator), + new YearMonthCodec(byteBufAllocator), - Codec codec = this.codecLookup.findDecodeCodec(dataType, format, Object.class); - if (codec instanceof CodecMetadata) { - return ((CodecMetadata) codec).type(); + // JSON + new JsonCodec(byteBufAllocator, preferAttachedBuffers), + new JsonByteArrayCodec(byteBufAllocator), + new JsonByteBufCodec(byteBufAllocator), + new JsonByteBufferCodec(byteBufAllocator), + new JsonInputStreamCodec(byteBufAllocator), + new JsonStringCodec(byteBufAllocator), + + // Fallback for Object.class + new ByteCodec(byteBufAllocator), + new DateCodec(byteBufAllocator, configuration::getZoneId), + + new BlobCodec(byteBufAllocator), + new ClobCodec(byteBufAllocator), + RefCursorCodec.INSTANCE, + RefCursorNameCodec.INSTANCE, + + // Array + new StringArrayCodec(byteBufAllocator), + + // Geometry + new CircleCodec(byteBufAllocator), + new PointCodec(byteBufAllocator), + new BoxCodec(byteBufAllocator), + new LineCodec(byteBufAllocator), + new LsegCodec(byteBufAllocator), + new PathCodec(byteBufAllocator), + new PolygonCodec(byteBufAllocator) + )); + + List> defaultArrayCodecs = new ArrayList<>(); + + for (Codec codec : codecs) { + + if (codec instanceof ArrayCodecDelegate) { + + Assert.requireType(codec, AbstractCodec.class, "Codec " + codec + " must be a subclass of AbstractCodec to be registered as generic array codec"); + ArrayCodecDelegate delegate = (ArrayCodecDelegate) codec; + Class componentType = delegate.type(); + + if (codec instanceof BoxCodec) { + // BOX[] uses a ';' as a delimiter (i.e. "{(3.7,4.6),(1.9,2.8);(5,7),(1.5,3.3)}") + defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate.getArrayDataType(), delegate, componentType, (byte) ';')); + } else if (codec instanceof AbstractNumericCodec) { + defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.NUMERIC_ARRAY_TYPES)); + } else if (codec instanceof AbstractTemporalCodec) { + defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.DATE_ARRAY_TYPES)); + } else { + defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate, componentType)); + } + } } - return null; - } + codecs.addAll(defaultArrayCodecs); - @Override - public Iterator> iterator() { - return Collections.unmodifiableList(new ArrayList<>(this.codecs)).iterator(); + return codecs; } } diff --git a/src/main/java/io/r2dbc/postgresql/codec/IntegerCodecDelegate.java b/src/main/java/io/r2dbc/postgresql/codec/IntegerCodecDelegate.java new file mode 100644 index 00000000..bbc97375 --- /dev/null +++ b/src/main/java/io/r2dbc/postgresql/codec/IntegerCodecDelegate.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.r2dbc.postgresql.client.EncodedParameter; +import io.r2dbc.postgresql.message.Format; +import io.r2dbc.postgresql.util.Assert; + +import java.util.function.Function; + +class IntegerCodecDelegate extends AbstractCodec { + + private final IntegerCodec delegate; + private final Function toIntegerConverter; + private final Function fromIntegerConverter; + + IntegerCodecDelegate(Class type, ByteBufAllocator byteBufAllocator, Function toIntegerConverter, Function fromIntegerConverter) { + super(type); + this.delegate = new IntegerCodec(byteBufAllocator); + this.toIntegerConverter = toIntegerConverter; + this.fromIntegerConverter = fromIntegerConverter; + } + + @Override + boolean doCanDecode(PostgresqlObjectId type, Format format) { + return delegate.doCanDecode(type, format); + } + + @Override + T doDecode(ByteBuf buffer, PostgresTypeIdentifier dataType, Format format, Class type) { + final Integer number = delegate.doDecode(buffer, dataType, format, Integer.TYPE); + return fromIntegerConverter.apply(number); + } + + @Override + EncodedParameter doEncode(T value) { + Assert.requireNonNull(value, "value must not be null"); + return delegate.doEncode(toIntegerConverter.apply(value)); + } + + @Override + EncodedParameter doEncode(T value, PostgresTypeIdentifier dataType) { + Assert.requireNonNull(value, "value must not be null"); + Assert.requireNonNull(dataType, "dataType must not be null"); + return delegate.doEncode(toIntegerConverter.apply(value), dataType); + } + + @Override + public Iterable getDataTypes() { + return delegate.getDataTypes(); + } + + @Override + public EncodedParameter encodeNull() { + return delegate.encodeNull(); + } +} diff --git a/src/main/java/io/r2dbc/postgresql/codec/MonthCodec.java b/src/main/java/io/r2dbc/postgresql/codec/MonthCodec.java new file mode 100644 index 00000000..239bacc1 --- /dev/null +++ b/src/main/java/io/r2dbc/postgresql/codec/MonthCodec.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBufAllocator; + +import java.time.Month; + +final class MonthCodec extends IntegerCodecDelegate { + + MonthCodec(ByteBufAllocator byteBufAllocator) { + super(Month.class, byteBufAllocator, Month::getValue, Month::of); + } +} diff --git a/src/main/java/io/r2dbc/postgresql/codec/MonthDayCodec.java b/src/main/java/io/r2dbc/postgresql/codec/MonthDayCodec.java new file mode 100644 index 00000000..5fed96e6 --- /dev/null +++ b/src/main/java/io/r2dbc/postgresql/codec/MonthDayCodec.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBufAllocator; + +import java.time.MonthDay; + +final class MonthDayCodec extends StringCodecDelegate { + + MonthDayCodec(ByteBufAllocator byteBufAllocator) { + super(MonthDay.class, byteBufAllocator, MonthDay::toString, MonthDay::parse); + } +} diff --git a/src/main/java/io/r2dbc/postgresql/codec/PeriodCodec.java b/src/main/java/io/r2dbc/postgresql/codec/PeriodCodec.java new file mode 100644 index 00000000..4b98e89a --- /dev/null +++ b/src/main/java/io/r2dbc/postgresql/codec/PeriodCodec.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBufAllocator; + +import java.time.Period; + +final class PeriodCodec extends StringCodecDelegate { + + PeriodCodec(ByteBufAllocator byteBufAllocator) { + super(Period.class, byteBufAllocator, Period::toString, Period::parse); + } +} diff --git a/src/main/java/io/r2dbc/postgresql/codec/YearCodec.java b/src/main/java/io/r2dbc/postgresql/codec/YearCodec.java new file mode 100644 index 00000000..e0763eeb --- /dev/null +++ b/src/main/java/io/r2dbc/postgresql/codec/YearCodec.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBufAllocator; + +import java.time.Year; + +final class YearCodec extends IntegerCodecDelegate { + + YearCodec(ByteBufAllocator byteBufAllocator) { + super(Year.class, byteBufAllocator, Year::getValue, Year::of); + } +} diff --git a/src/main/java/io/r2dbc/postgresql/codec/YearMonthCodec.java b/src/main/java/io/r2dbc/postgresql/codec/YearMonthCodec.java new file mode 100644 index 00000000..f1e8b167 --- /dev/null +++ b/src/main/java/io/r2dbc/postgresql/codec/YearMonthCodec.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBufAllocator; + +import java.time.YearMonth; + +final class YearMonthCodec extends StringCodecDelegate { + + YearMonthCodec(ByteBufAllocator byteBufAllocator) { + super(YearMonth.class, byteBufAllocator, YearMonth::toString, YearMonth::parse); + } +} diff --git a/src/main/resources/META-INF/native-image/org.postgresql/r2dbc-postgresql/reflect-config.json b/src/main/resources/META-INF/native-image/org.postgresql/r2dbc-postgresql/reflect-config.json index 9d0dc242..6656702e 100644 --- a/src/main/resources/META-INF/native-image/org.postgresql/r2dbc-postgresql/reflect-config.json +++ b/src/main/resources/META-INF/native-image/org.postgresql/r2dbc-postgresql/reflect-config.json @@ -1,4 +1,16 @@ [ + { + "name": "[Ljava.time.Period;", + "unsafeAllocated": true + }, + { + "name": "[Ljava.time.MonthDay;", + "unsafeAllocated": true + }, + { + "name": "[Ljava.time.YearMonth;", + "unsafeAllocated": true + }, { "name": "[Lio.r2dbc.postgresql.codec.Box;", "unsafeAllocated": true diff --git a/src/test/java/io/r2dbc/postgresql/AbstractCodecIntegrationTests.java b/src/test/java/io/r2dbc/postgresql/AbstractCodecIntegrationTests.java index 011813c1..7be6ca3c 100644 --- a/src/test/java/io/r2dbc/postgresql/AbstractCodecIntegrationTests.java +++ b/src/test/java/io/r2dbc/postgresql/AbstractCodecIntegrationTests.java @@ -21,22 +21,8 @@ import io.netty.buffer.Unpooled; import io.r2dbc.postgresql.api.PostgresqlResult; import io.r2dbc.postgresql.api.PostgresqlStatement; -import io.r2dbc.postgresql.codec.Box; -import io.r2dbc.postgresql.codec.Circle; -import io.r2dbc.postgresql.codec.EnumCodec; -import io.r2dbc.postgresql.codec.Json; -import io.r2dbc.postgresql.codec.Line; -import io.r2dbc.postgresql.codec.Lseg; -import io.r2dbc.postgresql.codec.Path; -import io.r2dbc.postgresql.codec.Point; -import io.r2dbc.postgresql.codec.Polygon; -import io.r2dbc.postgresql.codec.PostgresqlObjectId; -import io.r2dbc.spi.Blob; -import io.r2dbc.spi.Clob; -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.Parameters; -import io.r2dbc.spi.R2dbcType; -import io.r2dbc.spi.Type; +import io.r2dbc.postgresql.codec.*; +import io.r2dbc.spi.*; import org.assertj.core.data.Offset; import org.junit.jupiter.api.Test; import org.reactivestreams.Publisher; @@ -51,22 +37,10 @@ import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.net.UnknownHostException; +import java.net.*; import java.nio.Buffer; import java.nio.ByteBuffer; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; +import java.time.*; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.LinkedHashMap; @@ -75,6 +49,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.IntStream; import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST; import static org.assertj.core.api.Assertions.assertThat; @@ -578,6 +553,31 @@ void uuid() { testCodec(UUID.class, UUID.randomUUID(), "UUID"); } + @Test + void year() { + testCodec(Year.class, Year.now(), "INT4"); + } + + @Test + void month() { + IntStream.rangeClosed(1, 12).forEach(month -> testCodec(Month.class, Month.of(month), "INT4")); + } + + @Test + void dayOfWeek() { + IntStream.rangeClosed(1, 7).forEach(month -> testCodec(DayOfWeek.class, DayOfWeek.of(month), "INT4")); + } + + @Test + void monthDay() { + testCodec(MonthDay.class, MonthDay.now(), "VARCHAR"); + } + + @Test + void yearMonth() { + testCodec(YearMonth.class, YearMonth.now(), "VARCHAR"); + } + @Test void uuidArray() { testCodec(UUID[].class, new UUID[]{UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID()}, "UUID[]"); diff --git a/src/test/java/io/r2dbc/postgresql/codec/DayOfWeekCodecTest.java b/src/test/java/io/r2dbc/postgresql/codec/DayOfWeekCodecTest.java new file mode 100644 index 00000000..5036c3b2 --- /dev/null +++ b/src/test/java/io/r2dbc/postgresql/codec/DayOfWeekCodecTest.java @@ -0,0 +1,108 @@ +package io.r2dbc.postgresql.codec; + +import io.r2dbc.postgresql.client.EncodedParameter; +import io.r2dbc.postgresql.client.ParameterAssert; +import org.junit.jupiter.api.Test; + +import java.time.DayOfWeek; +import java.util.Arrays; +import java.util.function.Consumer; + +import static io.r2dbc.postgresql.client.EncodedParameter.NULL_VALUE; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.*; +import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY; +import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT; +import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class DayOfWeekCodecTest { + + @Test + void constructorNoByteBufAllocator() { + assertThatIllegalArgumentException().isThrownBy(() -> new DayOfWeekCodec(null)) + .withMessage("byteBufAllocator must not be null"); + } + + @Test + void decode() { + forEveryDayOfWeek(d -> + assertThat(new DayOfWeekCodec(TEST).decode(TEST.buffer().writeInt(d.getValue()), INT4, FORMAT_BINARY, DayOfWeek.class)).isEqualTo(d)); + } + + @Test + void decodeNoByteBuf() { + assertThat(new DayOfWeekCodec(TEST).decode(null, INT4.getObjectId(), FORMAT_BINARY, DayOfWeek.class)).isNull(); + } + + @Test + void doCanDecode() { + DayOfWeekCodec codec = new DayOfWeekCodec(TEST); + + assertThat(codec.doCanDecode(INT4, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(INT2, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(INT8, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(NUMERIC, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(VARCHAR, FORMAT_TEXT)).isFalse(); + } + + @Test + void doCanDecodeNoType() { + assertThatIllegalArgumentException().isThrownBy(() -> new DayOfWeekCodec(TEST).doCanDecode(null, FORMAT_BINARY)) + .withMessage("type must not be null"); + } + + @Test + void doEncodeInt() { + + forEveryDayOfWeek(d -> { + ParameterAssert.assertThat(new DayOfWeekCodec(TEST).doEncode(d)) + .hasFormat(FORMAT_BINARY) + .hasType(INT4.getObjectId()) + .hasValue(TEST.buffer().writeInt(d.getValue())); + }); + } + + @Test + void doEncodeShort() { + forEveryDayOfWeek(d -> { + ParameterAssert.assertThat(new DayOfWeekCodec(TEST).doEncode(d, INT2)) + .hasFormat(FORMAT_BINARY) + .hasType(INT2.getObjectId()) + .hasValue(TEST.buffer().writeShort(d.getValue())); + }); + } + + @Test + void doEncodeLong() { + + forEveryDayOfWeek(d -> { + ParameterAssert.assertThat(new DayOfWeekCodec(TEST).doEncode(d, INT8)) + .hasFormat(FORMAT_BINARY) + .hasType(INT8.getObjectId()) + .hasValue(TEST.buffer().writeLong(d.getValue())); + }); + } + + @Test + void doEncodeNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new DayOfWeekCodec(TEST).doEncode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeItemNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new DayOfWeekCodec(TEST).encode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeNull() { + ParameterAssert.assertThat(new DayOfWeekCodec(TEST).encodeNull()) + .isEqualTo(new EncodedParameter(FORMAT_BINARY, INT4.getObjectId(), NULL_VALUE)); + } + + private void forEveryDayOfWeek(Consumer assertion) { + Arrays.stream(DayOfWeek.values()).forEach(assertion); + } +} \ No newline at end of file diff --git a/src/test/java/io/r2dbc/postgresql/codec/MonthCodecTest.java b/src/test/java/io/r2dbc/postgresql/codec/MonthCodecTest.java new file mode 100644 index 00000000..6ff47167 --- /dev/null +++ b/src/test/java/io/r2dbc/postgresql/codec/MonthCodecTest.java @@ -0,0 +1,109 @@ +package io.r2dbc.postgresql.codec; + +import io.r2dbc.postgresql.client.EncodedParameter; +import io.r2dbc.postgresql.client.ParameterAssert; +import org.junit.jupiter.api.Test; + +import java.time.Month; +import java.util.Arrays; +import java.util.function.Consumer; + +import static io.r2dbc.postgresql.client.EncodedParameter.NULL_VALUE; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.*; +import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY; +import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT; +import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class MonthCodecTest { + + @Test + void constructorNoByteBufAllocator() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthCodec(null)) + .withMessage("byteBufAllocator must not be null"); + } + + + @Test + void decode() { + forEveryMonth(m -> + assertThat(new MonthCodec(TEST).decode(TEST.buffer().writeInt(m.getValue()), INT4, FORMAT_BINARY, Month.class)).isEqualTo(m)); + } + + @Test + void decodeNoByteBuf() { + assertThat(new MonthCodec(TEST).decode(null, INT4.getObjectId(), FORMAT_BINARY, Month.class)).isNull(); + } + + @Test + void doCanDecode() { + MonthCodec codec = new MonthCodec(TEST); + + assertThat(codec.doCanDecode(INT4, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(INT2, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(INT8, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(NUMERIC, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(VARCHAR, FORMAT_TEXT)).isFalse(); + } + + @Test + void doCanDecodeNoType() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthCodec(TEST).doCanDecode(null, FORMAT_BINARY)) + .withMessage("type must not be null"); + } + + @Test + void doEncodeInt() { + + forEveryMonth(m -> { + ParameterAssert.assertThat(new MonthCodec(TEST).doEncode(m)) + .hasFormat(FORMAT_BINARY) + .hasType(INT4.getObjectId()) + .hasValue(TEST.buffer().writeInt(m.getValue())); + }); + } + + @Test + void doEncodeShort() { + forEveryMonth(m -> { + ParameterAssert.assertThat(new MonthCodec(TEST).doEncode(m, INT2)) + .hasFormat(FORMAT_BINARY) + .hasType(INT2.getObjectId()) + .hasValue(TEST.buffer().writeShort(m.getValue())); + }); + } + + @Test + void doEncodeLong() { + + forEveryMonth(m -> { + ParameterAssert.assertThat(new MonthCodec(TEST).doEncode(m, INT8)) + .hasFormat(FORMAT_BINARY) + .hasType(INT8.getObjectId()) + .hasValue(TEST.buffer().writeLong(m.getValue())); + }); + } + + @Test + void doEncodeNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthCodec(TEST).doEncode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeItemNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthCodec(TEST).encode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeNull() { + ParameterAssert.assertThat(new MonthCodec(TEST).encodeNull()) + .isEqualTo(new EncodedParameter(FORMAT_BINARY, INT4.getObjectId(), NULL_VALUE)); + } + + private void forEveryMonth(Consumer assertion) { + Arrays.stream(Month.values()).forEach(assertion); + } +} \ No newline at end of file diff --git a/src/test/java/io/r2dbc/postgresql/codec/MonthDayCodecTest.java b/src/test/java/io/r2dbc/postgresql/codec/MonthDayCodecTest.java new file mode 100644 index 00000000..2865d0dc --- /dev/null +++ b/src/test/java/io/r2dbc/postgresql/codec/MonthDayCodecTest.java @@ -0,0 +1,98 @@ +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBuf; +import io.r2dbc.postgresql.client.EncodedParameter; +import io.r2dbc.postgresql.client.ParameterAssert; +import org.junit.jupiter.api.Test; + +import java.nio.charset.Charset; +import java.time.MonthDay; +import java.time.format.DateTimeParseException; + +import static io.r2dbc.postgresql.client.EncodedParameter.NULL_VALUE; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.BPCHAR; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.CHAR; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.NAME; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.TEXT; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.VARCHAR; +import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT; +import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class MonthDayCodecTest { + + @Test + void constructorNoByteBufAllocator() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthDayCodec(null)) + .withMessage("byteBufAllocator must not be null"); + } + + @Test + void decode() { + final MonthDay monthDay = MonthDay.now(); + + final ByteBuf buffer = TEST.buffer(); + + final int charsWritten = buffer.writeCharSequence(monthDay.toString(), Charset.defaultCharset()); + assertThat(charsWritten).isEqualTo(monthDay.toString().length()); + + assertThat(new MonthDayCodec(TEST) + .decode(buffer, VARCHAR, FORMAT_TEXT, MonthDay.class)) + .isEqualTo(monthDay); + } + + @Test + void decodeJunkString() { + final String junkString = "hello world"; + final ByteBuf buffer = TEST.buffer(); + + final int charsWritten = buffer.writeCharSequence(junkString, Charset.defaultCharset()); + assertThat(charsWritten).isEqualTo(junkString.length()); + + assertThatExceptionOfType(DateTimeParseException.class) + .isThrownBy(() -> new MonthDayCodec(TEST).decode(buffer, VARCHAR, FORMAT_TEXT, MonthDay.class)); + } + + @Test + void decodeNoByteBuf() { + assertThat(new MonthDayCodec(TEST).decode(null, VARCHAR.getObjectId(), FORMAT_TEXT, MonthDay.class)).isNull(); + } + + @Test + void doCanDecode() { + MonthDayCodec codec = new MonthDayCodec(TEST); + + assertThat(codec.doCanDecode(VARCHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(CHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(BPCHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(NAME, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(TEXT, FORMAT_TEXT)).isTrue(); + } + + @Test + void doCanDecodeNoType() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthDayCodec(TEST).doCanDecode(null, FORMAT_TEXT)) + .withMessage("type must not be null"); + } + + @Test + void doEncodeNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthDayCodec(TEST).doEncode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeItemNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new MonthDayCodec(TEST).encode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeNull() { + ParameterAssert.assertThat(new MonthDayCodec(TEST).encodeNull()) + .isEqualTo(new EncodedParameter(FORMAT_TEXT, VARCHAR.getObjectId(), NULL_VALUE)); + } + +} \ No newline at end of file diff --git a/src/test/java/io/r2dbc/postgresql/codec/PeriodCodecTest.java b/src/test/java/io/r2dbc/postgresql/codec/PeriodCodecTest.java new file mode 100644 index 00000000..b2678ab9 --- /dev/null +++ b/src/test/java/io/r2dbc/postgresql/codec/PeriodCodecTest.java @@ -0,0 +1,129 @@ +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBuf; +import io.r2dbc.postgresql.client.EncodedParameter; +import io.r2dbc.postgresql.client.ParameterAssert; +import org.junit.jupiter.api.Test; + +import java.nio.charset.Charset; +import java.time.Period; +import java.time.format.DateTimeParseException; + +import static io.r2dbc.postgresql.client.EncodedParameter.NULL_VALUE; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.BPCHAR; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.CHAR; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.NAME; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.TEXT; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.VARCHAR; +import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT; +import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class PeriodCodecTest { + + @Test + void constructorNoByteBufAllocator() { + assertThatIllegalArgumentException().isThrownBy(() -> new PeriodCodec(null)) + .withMessage("byteBufAllocator must not be null"); + } + + @Test + void decodeDays() { + final int days = 4; + + final Period period = Period.ofDays(days); + assertDecodeOfPeriod(period); + } + + @Test + void decodeJunkString() { + final String junkString = "hello world"; + final ByteBuf buffer = TEST.buffer(); + + final int charsWritten = buffer.writeCharSequence(junkString, Charset.defaultCharset()); + assertThat(charsWritten).isEqualTo(junkString.length()); + + assertThatExceptionOfType(DateTimeParseException.class) + .isThrownBy(() -> new PeriodCodec(TEST).decode(buffer, VARCHAR, FORMAT_TEXT, Period.class)); + } + + @Test + void decodeMonths() { + final int months = 3; + + final Period period = Period.ofMonths(months); + assertDecodeOfPeriod(period); + } + + @Test + void decodeNoByteBuf() { + assertThat(new PeriodCodec(TEST).decode(null, VARCHAR.getObjectId(), FORMAT_TEXT, Period.class)).isNull(); + } + + @Test + void decodeWeeks() { + final int weeks = 7; + + final Period period = Period.ofWeeks(weeks); + assertDecodeOfPeriod(period); + } + + @Test + void decodeYearsMonthsDays() { + final int years = 5; + final int months = 4; + final int days = 7; + + final Period period = Period.of(years, months, days); + assertDecodeOfPeriod(period); + } + + @Test + void doCanDecode() { + final PeriodCodec codec = new PeriodCodec(TEST); + + assertThat(codec.doCanDecode(VARCHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(CHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(BPCHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(NAME, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(TEXT, FORMAT_TEXT)).isTrue(); + } + + @Test + void doCanDecodeNoType() { + assertThatIllegalArgumentException().isThrownBy(() -> new PeriodCodec(TEST).doCanDecode(null, FORMAT_TEXT)) + .withMessage("type must not be null"); + } + + @Test + void doEncodeNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new PeriodCodec(TEST).doEncode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeItemNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new PeriodCodec(TEST).encode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeNull() { + ParameterAssert.assertThat(new PeriodCodec(TEST).encodeNull()) + .isEqualTo(new EncodedParameter(FORMAT_TEXT, VARCHAR.getObjectId(), NULL_VALUE)); + } + + private static void assertDecodeOfPeriod(Period period) { + final ByteBuf buffer = TEST.buffer(); + + final int charsWritten = buffer.writeCharSequence(period.toString(), Charset.defaultCharset()); + assertThat(charsWritten).isEqualTo(period.toString().length()); + + assertThat(new PeriodCodec(TEST) + .decode(buffer, VARCHAR, FORMAT_TEXT, Period.class)) + .isEqualTo(period); + } + +} \ No newline at end of file diff --git a/src/test/java/io/r2dbc/postgresql/codec/YearCodecTest.java b/src/test/java/io/r2dbc/postgresql/codec/YearCodecTest.java new file mode 100644 index 00000000..96d78e59 --- /dev/null +++ b/src/test/java/io/r2dbc/postgresql/codec/YearCodecTest.java @@ -0,0 +1,112 @@ +package io.r2dbc.postgresql.codec; + +import io.r2dbc.postgresql.client.EncodedParameter; +import io.r2dbc.postgresql.client.ParameterAssert; +import org.junit.jupiter.api.Test; + +import java.time.Year; + +import static io.r2dbc.postgresql.client.EncodedParameter.NULL_VALUE; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.INT2; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.INT4; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.INT8; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.NUMERIC; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.VARCHAR; +import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY; +import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT; +import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class YearCodecTest { + + @Test + void constructorNoByteBufAllocator() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearCodec(null)) + .withMessage("byteBufAllocator must not be null"); + } + + @Test + void decode() { + Year year = Year.now(); + + assertThat(new YearCodec(TEST).decode(TEST.buffer().writeInt(year.getValue()), INT4, FORMAT_BINARY, Year.class)) + .isEqualTo(year); + } + + @Test + void decodeNoByteBuf() { + assertThat(new YearCodec(TEST).decode(null, INT4.getObjectId(), FORMAT_BINARY, Year.class)).isNull(); + } + + @Test + void doCanDecode() { + YearCodec codec = new YearCodec(TEST); + + assertThat(codec.doCanDecode(INT4, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(INT2, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(INT8, FORMAT_BINARY)).isTrue(); + assertThat(codec.doCanDecode(NUMERIC, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(VARCHAR, FORMAT_TEXT)).isFalse(); + } + + @Test + void doCanDecodeNoType() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearCodec(TEST).doCanDecode(null, FORMAT_BINARY)) + .withMessage("type must not be null"); + } + + @Test + void doEncodeInt() { + Year year = Year.now(); + + ParameterAssert.assertThat(new YearCodec(TEST).doEncode(year)) + .hasFormat(FORMAT_BINARY) + .hasType(INT4.getObjectId()) + .hasValue(TEST.buffer().writeInt(year.getValue())); + } + + @Test + void doEncodeLong() { + Year year = Year.now(); + + ParameterAssert.assertThat(new YearCodec(TEST).doEncode(year, INT8)) + .hasFormat(FORMAT_BINARY) + .hasType(INT8.getObjectId()) + .hasValue(TEST.buffer().writeLong(year.getValue())); + } + + @Test + void doEncodeNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearCodec(TEST).doEncode(null)) + .withMessage("value must not be null"); + } + + @Test + void doEncodeShort() { + Year year = Year.now(); + + ParameterAssert.assertThat(new YearCodec(TEST).doEncode(year, INT2)) + .hasFormat(FORMAT_BINARY) + .hasType(INT2.getObjectId()) + .hasValue(TEST.buffer().writeShort(year.getValue())); + } + + @Test + void encodeItemNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearCodec(TEST).encode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeNull() { + ParameterAssert.assertThat(new YearCodec(TEST).encodeNull()) + .isEqualTo(new EncodedParameter(FORMAT_BINARY, INT4.getObjectId(), NULL_VALUE)); + } + + @Test + void myTest() { + + } + +} \ No newline at end of file diff --git a/src/test/java/io/r2dbc/postgresql/codec/YearMonthCodecTest.java b/src/test/java/io/r2dbc/postgresql/codec/YearMonthCodecTest.java new file mode 100644 index 00000000..40173b4a --- /dev/null +++ b/src/test/java/io/r2dbc/postgresql/codec/YearMonthCodecTest.java @@ -0,0 +1,98 @@ +package io.r2dbc.postgresql.codec; + +import io.netty.buffer.ByteBuf; +import io.r2dbc.postgresql.client.EncodedParameter; +import io.r2dbc.postgresql.client.ParameterAssert; +import org.junit.jupiter.api.Test; + +import java.nio.charset.Charset; +import java.time.YearMonth; +import java.time.format.DateTimeParseException; + +import static io.r2dbc.postgresql.client.EncodedParameter.NULL_VALUE; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.BPCHAR; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.CHAR; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.NAME; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.TEXT; +import static io.r2dbc.postgresql.codec.PostgresqlObjectId.VARCHAR; +import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT; +import static io.r2dbc.postgresql.util.TestByteBufAllocator.TEST; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class YearMonthCodecTest { + + @Test + void constructorNoByteBufAllocator() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearMonthCodec(null)) + .withMessage("byteBufAllocator must not be null"); + } + + @Test + void decode() { + final YearMonth yearMonth = YearMonth.now(); + + final ByteBuf buffer = TEST.buffer(); + + final int charsWritten = buffer.writeCharSequence(yearMonth.toString(), Charset.defaultCharset()); + assertThat(charsWritten).isEqualTo(yearMonth.toString().length()); + + assertThat(new YearMonthCodec(TEST) + .decode(buffer, VARCHAR, FORMAT_TEXT, YearMonth.class)) + .isEqualTo(yearMonth); + } + + @Test + void decodeJunkString() { + final String junkString = "hello world"; + final ByteBuf buffer = TEST.buffer(); + + final int charsWritten = buffer.writeCharSequence(junkString, Charset.defaultCharset()); + assertThat(charsWritten).isEqualTo(junkString.length()); + + assertThatExceptionOfType(DateTimeParseException.class) + .isThrownBy(() -> new YearMonthCodec(TEST).decode(buffer, VARCHAR, FORMAT_TEXT, YearMonth.class)); + } + + @Test + void decodeNoByteBuf() { + assertThat(new YearMonthCodec(TEST).decode(null, VARCHAR.getObjectId(), FORMAT_TEXT, YearMonth.class)).isNull(); + } + + @Test + void doCanDecode() { + YearMonthCodec codec = new YearMonthCodec(TEST); + + assertThat(codec.doCanDecode(VARCHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(CHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(BPCHAR, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(NAME, FORMAT_TEXT)).isTrue(); + assertThat(codec.doCanDecode(TEXT, FORMAT_TEXT)).isTrue(); + } + + @Test + void doCanDecodeNoType() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearMonthCodec(TEST).doCanDecode(null, FORMAT_TEXT)) + .withMessage("type must not be null"); + } + + @Test + void doEncodeNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearMonthCodec(TEST).doEncode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeItemNoValue() { + assertThatIllegalArgumentException().isThrownBy(() -> new YearMonthCodec(TEST).encode(null)) + .withMessage("value must not be null"); + } + + @Test + void encodeNull() { + ParameterAssert.assertThat(new YearMonthCodec(TEST).encodeNull()) + .isEqualTo(new EncodedParameter(FORMAT_TEXT, VARCHAR.getObjectId(), NULL_VALUE)); + } + +} \ No newline at end of file From 939da476a2a55d7a7f48234afc5d530cbfcf1e6f Mon Sep 17 00:00:00 2001 From: steverigney Date: Sun, 27 Aug 2023 15:58:06 +0100 Subject: [PATCH 2/3] updating the readme for java 8 temporal codecs - gh-591 --- README.md | 163 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 85 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index a5e97a7b..e533e266 100644 --- a/README.md +++ b/README.md @@ -424,89 +424,89 @@ When available, the driver registers also an array variant of the codec. This reference table shows the type mapping between [PostgreSQL][p] and Java data types: -| PostgreSQL Type | Supported Data Type | -|:------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| -| [`bigint`][psql-bigint-ref] | [**`Long`**][java-long-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | -| [`bit`][psql-bit-ref] | Not yet supported.| -| [`bit varying`][psql-bit-ref] | Not yet supported.| -| [`boolean or bool`][psql-boolean-ref] | [`Boolean`][java-boolean-ref]| -| [`box`][psql-box-ref] | **`Box`**| -| [`bytea`][psql-bytea-ref] | [**`ByteBuffer`**][java-ByteBuffer-ref], [`byte[]`][java-byte-ref], [`Blob`][r2dbc-blob-ref]| -| [`character`][psql-character-ref] | [`String`][java-string-ref]| -| [`character varying`][psql-character-ref] | [`String`][java-string-ref]| -| [`cidr`][psql-cidr-ref] | Not yet supported.| -| [`circle`][psql-circle-ref] | **`Circle`**| -| [`date`][psql-date-ref] | [`LocalDate`][java-ld-ref]| -| [`double precision`][psql-floating-point-ref] | [**`Double`**][java-double-ref], [`Float`][java-float-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref]| -| [enumerated types][psql-enum-ref] | Client code `Enum` types through `EnumCodec`| -| [`geometry`][postgis-ref] | **`org.locationtech.jts.geom.Geometry`**| -| [`hstore`][psql-hstore-ref] | [**`Map`**][java-map-ref]| -| [`inet`][psql-inet-ref] | [**`InetAddress`**][java-inet-ref]| -| [`integer`][psql-integer-ref] | [**`Integer`**][java-integer-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref]| -| [`interval`][psql-interval-ref] | **`Interval`**| -| [`json`][psql-json-ref] | **`Json`**, [`String`][java-string-ref]. Reading: `ByteBuf`[`byte[]`][java-primitive-ref], [`ByteBuffer`][java-ByteBuffer-ref], [`String`][java-string-ref], [`InputStream`][java-inputstream-ref]| -| [`jsonb`][psql-json-ref] | **`Json`**, [`String`][java-string-ref]. Reading: `ByteBuf`[`byte[]`][java-primitive-ref], [`ByteBuffer`][java-ByteBuffer-ref], [`String`][java-string-ref], [`InputStream`][java-inputstream-ref]| -| [`line`][psql-line-ref] | **`Line`**| -| [`lseg`][psql-lseq-ref] | **`Lseg`**| -| [`macaddr`][psql-macaddr-ref] | Not yet supported.| -| [`macaddr8`][psql-macaddr8-ref] | Not yet supported.| -| [`money`][psql-money-ref] | Not yet supported. Please don't use this type. It is a very poor implementation. | -| [`name`][psql-name-ref] | [**`String`**][java-string-ref] -| [`numeric`][psql-bignumeric-ref] | [`BigDecimal`][java-bigdecimal-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigInteger`][java-biginteger-ref]| -| [`oid`][psql-oid-ref] | [**`Integer`**][java-integer-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref]| -| [`path`][psql-path-ref] | **`Path`**| -| [`pg_lsn`][psql-pg_lsn-ref] | Not yet supported.| -| [`point`][psql-point-ref] | **`Point`**| -| [`polygon`][psql-polygon-ref] | **`Polygon`**| -| [`real`][psql-real-ref] | [**`Float`**][java-float-ref], [`Double`][java-double-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref]| -| [`smallint`][psql-smallint-ref] | [**`Short`**][java-short-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref]| -| [`smallserial`][psql-smallserial-ref] | [**`Integer`**][java-integer-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref]| -| [`serial`][psql-serial-ref] | [**`Long`**][java-long-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref]| -| [`text`][psql-text-ref] | [**`String`**][java-string-ref], [`Clob`][r2dbc-clob-ref]| -| [`time [without time zone]`][psql-time-ref] | [`LocalTime`][java-lt-ref]| -| [`time [with time zone]`][psql-time-ref] | [`OffsetTime`][java-ot-ref]| -| [`timestamp [without time zone]`][psql-time-ref]|[**`LocalDateTime`**][java-ldt-ref], [`LocalTime`][java-lt-ref], [`LocalDate`][java-ld-ref], [`java.util.Date`][java-legacy-date-ref]| -| [`timestamp [with time zone]`][psql-time-ref] | [**`OffsetDatetime`**][java-odt-ref], [`ZonedDateTime`][java-zdt-ref], [`Instant`][java-instant-ref]| -| [`tsquery`][psql-tsquery-ref] | Not yet supported.| -| [`tsvector`][psql-tsvector-ref] | Not yet supported.| -| [`txid_snapshot`][psql-txid_snapshot-ref] | Not yet supported.| -| [`uuid`][psql-uuid-ref] | [**`UUID`**][java-uuid-ref], [`String`][java-string-ref]|| -| [`xml`][psql-xml-ref] | Not yet supported. | +| PostgreSQL Type | Supported Data Type | +|:-------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [`bigint`][psql-bigint-ref] | [**`Long`**][java-long-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | +| [`bit`][psql-bit-ref] | Not yet supported. | +| [`bit varying`][psql-bit-ref] | Not yet supported. | +| [`boolean or bool`][psql-boolean-ref] | [`Boolean`][java-boolean-ref] | +| [`box`][psql-box-ref] | **`Box`** | +| [`bytea`][psql-bytea-ref] | [**`ByteBuffer`**][java-ByteBuffer-ref], [`byte[]`][java-byte-ref], [`Blob`][r2dbc-blob-ref] | +| [`character`][psql-character-ref] | [`String`][java-string-ref] | +| [`character varying`][psql-character-ref] | [`String`][java-string-ref], [`YearMonth`][java-yearmonth-ref],[`MonthDay`][java-monthday-ref], [`Period`][java-period-ref] | +| [`cidr`][psql-cidr-ref] | Not yet supported. | +| [`circle`][psql-circle-ref] | **`Circle`** | +| [`date`][psql-date-ref] | [`LocalDate`][java-ld-ref] | +| [`double precision`][psql-floating-point-ref] | [**`Double`**][java-double-ref], [`Float`][java-float-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | +| [enumerated types][psql-enum-ref] | Client code `Enum` types through `EnumCodec` | +| [`geometry`][postgis-ref] | **`org.locationtech.jts.geom.Geometry`** | +| [`hstore`][psql-hstore-ref] | [**`Map`**][java-map-ref] | +| [`inet`][psql-inet-ref] | [**`InetAddress`**][java-inet-ref] | +| [`integer`][psql-integer-ref] | [**`Integer`**][java-integer-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref], [`Year`][java-year-ref], [`Month`][java-month-ref], [`DayOfWeek`][java-dow-ref] | +| [`interval`][psql-interval-ref] | **`Interval`** | +| [`json`][psql-json-ref] | **`Json`**, [`String`][java-string-ref]. Reading: `ByteBuf`[`byte[]`][java-primitive-ref], [`ByteBuffer`][java-ByteBuffer-ref], [`String`][java-string-ref], [`InputStream`][java-inputstream-ref] | +| [`jsonb`][psql-json-ref] | **`Json`**, [`String`][java-string-ref]. Reading: `ByteBuf`[`byte[]`][java-primitive-ref], [`ByteBuffer`][java-ByteBuffer-ref], [`String`][java-string-ref], [`InputStream`][java-inputstream-ref] | +| [`line`][psql-line-ref] | **`Line`** | +| [`lseg`][psql-lseq-ref] | **`Lseg`** | +| [`macaddr`][psql-macaddr-ref] | Not yet supported. | +| [`macaddr8`][psql-macaddr8-ref] | Not yet supported. | +| [`money`][psql-money-ref] | Not yet supported. Please don't use this type. It is a very poor implementation. | +| [`name`][psql-name-ref] | [**`String`**][java-string-ref] +| [`numeric`][psql-bignumeric-ref] | [`BigDecimal`][java-bigdecimal-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigInteger`][java-biginteger-ref] | +| [`oid`][psql-oid-ref] | [**`Integer`**][java-integer-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | +| [`path`][psql-path-ref] | **`Path`** | +| [`pg_lsn`][psql-pg_lsn-ref] | Not yet supported. | +| [`point`][psql-point-ref] | **`Point`** | +| [`polygon`][psql-polygon-ref] | **`Polygon`** | +| [`real`][psql-real-ref] | [**`Float`**][java-float-ref], [`Double`][java-double-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | +| [`smallint`][psql-smallint-ref] | [**`Short`**][java-short-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Integer`][java-integer-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | +| [`smallserial`][psql-smallserial-ref] | [**`Integer`**][java-integer-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Long`][java-long-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | +| [`serial`][psql-serial-ref] | [**`Long`**][java-long-ref], [`Boolean`][java-boolean-ref], [`Byte`][java-byte-ref], [`Short`][java-short-ref], [`Integer`][java-integer-ref], [`BigDecimal`][java-bigdecimal-ref], [`BigInteger`][java-biginteger-ref] | +| [`text`][psql-text-ref] | [**`String`**][java-string-ref], [`Clob`][r2dbc-clob-ref] | +| [`time [without time zone]`][psql-time-ref] | [`LocalTime`][java-lt-ref] | +| [`time [with time zone]`][psql-time-ref] | [`OffsetTime`][java-ot-ref] | +| [`timestamp [without time zone]`][psql-time-ref] | [**`LocalDateTime`**][java-ldt-ref], [`LocalTime`][java-lt-ref], [`LocalDate`][java-ld-ref], [`java.util.Date`][java-legacy-date-ref] | +| [`timestamp [with time zone]`][psql-time-ref] | [**`OffsetDatetime`**][java-odt-ref], [`ZonedDateTime`][java-zdt-ref], [`Instant`][java-instant-ref] | +| [`tsquery`][psql-tsquery-ref] | Not yet supported. | +| [`tsvector`][psql-tsvector-ref] | Not yet supported. | +| [`txid_snapshot`][psql-txid_snapshot-ref] | Not yet supported. | +| [`uuid`][psql-uuid-ref] | [**`UUID`**][java-uuid-ref], [`String`][java-string-ref] || +| [`xml`][psql-xml-ref] | Not yet supported. | Types in **bold** indicate the native (default) Java type. Support for the following single-dimensional arrays (read and write): -| PostgreSQL Type | Supported Data Type | -|:------------------------------------------------|:--------------------------------------| -| [`bytea[]`][psql-bytea-ref] | [**`ByteBuffer[]`**][java-ByteBuffer-ref], [`byte[][]`][java-byte-ref]| -| [`boolean[] or bool[]`][psql-boolean-ref] | [`Boolean[]`][java-boolean-ref] | -| [`box[]`][psql-box-ref] | **`Box[]`**| -| [`character`][psql-character-ref] | [`String[]`][java-string-ref]| -| [`character varying`][psql-character-ref] | [`String[]`][java-string-ref]| -| [`circle[]`][psql-circle-ref] | **`Circle[]`**| -| [`date[]`][psql-date-ref] | [`LocalDate[]`][java-ld-ref]| -| [`double precision[]`][psql-floating-point-ref] | [**`Double[]`**][java-double-ref], [`Float[]`][java-float-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref]| -| [enumerated type arrays][psql-enum-ref] | Client code `Enum[]` types through `EnumCodec`| -| [`inet[]`][psql-inet-ref] | [**`InetAddress[]`**][java-inet-ref]| -| [`integer`[]][psql-integer-ref] | [**`Integer[]`**][java-integer-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref]| -| [`interval[]`][psql-interval-ref] | **`Interval[]`**| -| [`line[]`][psql-line-ref] | **`Line[]`**| -| [`lseg[]`][psql-lseq-ref] | **`Lseg[]`**| -| [`numeric[]`][psql-bignumeric-ref] | [`BigDecimal[]`][java-bigdecimal-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigInteger[]`][java-biginteger-ref]| -| [`path[]`][psql-path-ref] | **`Path[]`**| -| [`point[]`][psql-point-ref] | **`Point[]`**| -| [`polygon[]`][psql-polygon-ref] | **`Polygon[]`**| -| [`real[]`][psql-real-ref] | [**`Float[]`**][java-float-ref], [`Double[]`][java-double-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref]| -| [`smallint[]`][psql-smallint-ref] | [**`Short[]`**][java-short-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref]| -| [`smallserial[]`][psql-smallserial-ref] | [**`Integer[]`**][java-integer-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref]| -| [`serial[]`][psql-serial-ref] | [**`Long[]`**][java-long-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref]| -| [`text[]`][psql-text-ref] | [`String[]`][java-string-ref] | -| [`time[] [without time zone]`][psql-time-ref] | [`LocalTime[]`][java-lt-ref]| -| [`time[] [with time zone]`][psql-time-ref] | [`OffsetTime[]`][java-ot-ref]| -| [`timestamp[] [without time zone]`][psql-time-ref]|[**`LocalDateTime[]`**][java-ldt-ref], [`LocalTime[]`][java-lt-ref], [`LocalDate[]`][java-ld-ref], [`java.util.Date[]`][java-legacy-date-ref]| -| [`timestamp[] [with time zone]`][psql-time-ref] | [**`OffsetDatetime[]`**][java-odt-ref], [`ZonedDateTime[]`][java-zdt-ref], [`Instant[]`][java-instant-ref]| -| [`uuid[]`][psql-uuid-ref] | [**`UUID[]`**][java-uuid-ref], [`String[]`][java-string-ref]|| +| PostgreSQL Type | Supported Data Type | +|:------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [`bytea[]`][psql-bytea-ref] | [**`ByteBuffer[]`**][java-ByteBuffer-ref], [`byte[][]`][java-byte-ref] | +| [`boolean[] or bool[]`][psql-boolean-ref] | [`Boolean[]`][java-boolean-ref] | +| [`box[]`][psql-box-ref] | **`Box[]`** | +| [`character`][psql-character-ref] | [`String[]`][java-string-ref] | +| [`character varying`][psql-character-ref] | [`String[]`][java-string-ref], [`YearMonth[]`][java-yearmonth-ref], [`Period[]`][java-period-ref], [`MonthDay[]`][java-monthday-ref] | +| [`circle[]`][psql-circle-ref] | **`Circle[]`** | +| [`date[]`][psql-date-ref] | [`LocalDate[]`][java-ld-ref] | +| [`double precision[]`][psql-floating-point-ref] | [**`Double[]`**][java-double-ref], [`Float[]`][java-float-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref] | +| [enumerated type arrays][psql-enum-ref] | Client code `Enum[]` types through `EnumCodec` | +| [`inet[]`][psql-inet-ref] | [**`InetAddress[]`**][java-inet-ref] | +| [`integer`[]][psql-integer-ref] | [**`Integer[]`**][java-integer-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref] | +| [`interval[]`][psql-interval-ref] | **`Interval[]`** | +| [`line[]`][psql-line-ref] | **`Line[]`** | +| [`lseg[]`][psql-lseq-ref] | **`Lseg[]`** | +| [`numeric[]`][psql-bignumeric-ref] | [`BigDecimal[]`][java-bigdecimal-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigInteger[]`][java-biginteger-ref] | +| [`path[]`][psql-path-ref] | **`Path[]`** | +| [`point[]`][psql-point-ref] | **`Point[]`** | +| [`polygon[]`][psql-polygon-ref] | **`Polygon[]`** | +| [`real[]`][psql-real-ref] | [**`Float[]`**][java-float-ref], [`Double[]`][java-double-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref] | +| [`smallint[]`][psql-smallint-ref] | [**`Short[]`**][java-short-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Integer[]`][java-integer-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref] | +| [`smallserial[]`][psql-smallserial-ref] | [**`Integer[]`**][java-integer-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Long[]`][java-long-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref] | +| [`serial[]`][psql-serial-ref] | [**`Long[]`**][java-long-ref], [`Boolean[]`][java-boolean-ref], [`Byte[]`][java-byte-ref], [`Short[]`][java-short-ref], [`Integer[]`][java-integer-ref], [`BigDecimal[]`][java-bigdecimal-ref], [`BigInteger[]`][java-biginteger-ref] | +| [`text[]`][psql-text-ref] | [`String[]`][java-string-ref] | +| [`time[] [without time zone]`][psql-time-ref] | [`LocalTime[]`][java-lt-ref] | +| [`time[] [with time zone]`][psql-time-ref] | [`OffsetTime[]`][java-ot-ref] | +| [`timestamp[] [without time zone]`][psql-time-ref]| [**`LocalDateTime[]`**][java-ldt-ref], [`LocalTime[]`][java-lt-ref], [`LocalDate[]`][java-ld-ref], [`java.util.Date[]`][java-legacy-date-ref] | +| [`timestamp[] [with time zone]`][psql-time-ref] | [**`OffsetDatetime[]`**][java-odt-ref], [`ZonedDateTime[]`][java-zdt-ref], [`Instant[]`][java-instant-ref] | +| [`uuid[]`][psql-uuid-ref] | [**`UUID[]`**][java-uuid-ref], [`String[]`][java-string-ref] || [psql-bigint-ref]: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT [psql-bit-ref]: https://www.postgresql.org/docs/current/datatype-numeric.html @@ -559,6 +559,8 @@ Support for the following single-dimensional arrays (read and write): [java-byte-ref]: https://docs.oracle.com/javase/8/docs/api/java/lang/Byte.html [java-ByteBuffer-ref]: https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html [java-double-ref]: https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html +[java-dow-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html +[java-duration-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html [java-float-ref]: https://docs.oracle.com/javase/8/docs/api/java/lang/Float.html [java-map-ref]: https://docs.oracle.com/javase/8/docs/api/java/util/Map.html [java-inet-ref]: https://docs.oracle.com/javase/8/docs/api/java/net/InetAddress.html @@ -570,12 +572,17 @@ Support for the following single-dimensional arrays (read and write): [java-ld-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html [java-lt-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html [java-legacy-date-ref]: https://docs.oracle.com/javase/8/docs/api/java/util/Date.html +[java-month-ref]: https://docs.oracle.com/javase/8/docs/api/java/util/Month.html +[java-monthday-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/MonthDay.html [java-odt-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html [java-ot-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/OffsetTime.html +[java-period-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/Period.html [java-primitive-ref]: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html [java-short-ref]: https://docs.oracle.com/javase/8/docs/api/java/lang/Short.html [java-string-ref]: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html [java-uuid-ref]: https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html +[java-year-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/Year.html +[java-yearmonth-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/YearMonth.html [java-zdt-ref]: https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html ## Extension mechanism From 4b698d93cd44b681b3815b4d69afd8c53e19c701 Mon Sep 17 00:00:00 2001 From: steverigney Date: Sat, 2 Sep 2023 12:33:20 +0100 Subject: [PATCH 3/3] undoing accidental reformatting of Default codecs - gh-591 --- .../r2dbc/postgresql/codec/DefaultCodecs.java | 238 +++++++++--------- 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java b/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java index 16e24074..1001ba57 100644 --- a/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java +++ b/src/main/java/io/r2dbc/postgresql/codec/DefaultCodecs.java @@ -44,10 +44,10 @@ */ public final class DefaultCodecs implements Codecs, CodecRegistry { - private final CodecLookup codecLookup; - private final List> codecs; + private final CodecLookup codecLookup; + /** * Create a new instance of {@link DefaultCodecs} preferring detached (copied buffers). * @@ -96,6 +96,103 @@ public DefaultCodecs(ByteBufAllocator byteBufAllocator, boolean preferAttachedBu this.codecLookup.afterCodecAdded(); } + @SuppressWarnings({"unchecked", "rawtypes"}) + private static List> getDefaultCodecs(ByteBufAllocator byteBufAllocator, boolean preferAttachedBuffers, CodecConfiguration configuration) { + + List> codecs = new CopyOnWriteArrayList<>(Arrays.asList( + + // Prioritized Codecs + new StringCodec(byteBufAllocator), + new InstantCodec(byteBufAllocator, configuration::getZoneId), + new ZonedDateTimeCodec(byteBufAllocator), + new BinaryByteBufferCodec(byteBufAllocator), + new BinaryByteArrayCodec(byteBufAllocator), + + new BigDecimalCodec(byteBufAllocator), + new BigIntegerCodec(byteBufAllocator), + new BooleanCodec(byteBufAllocator), + new CharacterCodec(byteBufAllocator), + new DoubleCodec(byteBufAllocator), + new FloatCodec(byteBufAllocator), + new InetAddressCodec(byteBufAllocator), + new IntegerCodec(byteBufAllocator), + new IntervalCodec(byteBufAllocator), + new LocalDateCodec(byteBufAllocator), + new LocalDateTimeCodec(byteBufAllocator, configuration::getZoneId), + new LocalTimeCodec(byteBufAllocator), + new LongCodec(byteBufAllocator), + new OffsetDateTimeCodec(byteBufAllocator), + new OffsetTimeCodec(byteBufAllocator), + new ShortCodec(byteBufAllocator), + new UriCodec(byteBufAllocator), + new UrlCodec(byteBufAllocator), + new UuidCodec(byteBufAllocator), + new ZoneIdCodec(byteBufAllocator), + new DayOfWeekCodec(byteBufAllocator), + new MonthCodec(byteBufAllocator), + new MonthDayCodec(byteBufAllocator), + new PeriodCodec(byteBufAllocator), + new YearCodec(byteBufAllocator), + new YearMonthCodec(byteBufAllocator), + + // JSON + new JsonCodec(byteBufAllocator, preferAttachedBuffers), + new JsonByteArrayCodec(byteBufAllocator), + new JsonByteBufCodec(byteBufAllocator), + new JsonByteBufferCodec(byteBufAllocator), + new JsonInputStreamCodec(byteBufAllocator), + new JsonStringCodec(byteBufAllocator), + + // Fallback for Object.class + new ByteCodec(byteBufAllocator), + new DateCodec(byteBufAllocator, configuration::getZoneId), + + new BlobCodec(byteBufAllocator), + new ClobCodec(byteBufAllocator), + RefCursorCodec.INSTANCE, + RefCursorNameCodec.INSTANCE, + + // Array + new StringArrayCodec(byteBufAllocator), + + // Geometry + new CircleCodec(byteBufAllocator), + new PointCodec(byteBufAllocator), + new BoxCodec(byteBufAllocator), + new LineCodec(byteBufAllocator), + new LsegCodec(byteBufAllocator), + new PathCodec(byteBufAllocator), + new PolygonCodec(byteBufAllocator) + )); + + List> defaultArrayCodecs = new ArrayList<>(); + + for (Codec codec : codecs) { + + if (codec instanceof ArrayCodecDelegate) { + + Assert.requireType(codec, AbstractCodec.class, "Codec " + codec + " must be a subclass of AbstractCodec to be registered as generic array codec"); + ArrayCodecDelegate delegate = (ArrayCodecDelegate) codec; + Class componentType = delegate.type(); + + if (codec instanceof BoxCodec) { + // BOX[] uses a ';' as a delimiter (i.e. "{(3.7,4.6),(1.9,2.8);(5,7),(1.5,3.3)}") + defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate.getArrayDataType(), delegate, componentType, (byte) ';')); + } else if (codec instanceof AbstractNumericCodec) { + defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.NUMERIC_ARRAY_TYPES)); + } else if (codec instanceof AbstractTemporalCodec) { + defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.DATE_ARRAY_TYPES)); + } else { + defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate, componentType)); + } + } + } + + codecs.addAll(defaultArrayCodecs); + + return codecs; + } + @Override public void addFirst(Codec codec) { Assert.requireNonNull(codec, "codec must not be null"); @@ -173,35 +270,6 @@ public EncodedParameter encode(Object value) { return encodeParameterValue(value, dataType, parameterValue); } - @Override - public EncodedParameter encodeNull(Class type) { - Assert.requireNonNull(type, "type must not be null"); - - Codec codec = this.codecLookup.findEncodeNullCodec(type); - if (codec != null) { - return codec.encodeNull(); - } - - throw new IllegalArgumentException(String.format("Cannot encode null parameter of type %s", type.getName())); - } - - @Override - public Iterator> iterator() { - return Collections.unmodifiableList(new ArrayList<>(this.codecs)).iterator(); - } - - @Override - public Class preferredType(int dataType, Format format) { - Assert.requireNonNull(format, "format must not be null"); - - Codec codec = this.codecLookup.findDecodeCodec(dataType, format, Object.class); - if (codec instanceof CodecMetadata) { - return ((CodecMetadata) codec).type(); - } - - return null; - } - EncodedParameter encodeParameterValue(Object value, @Nullable PostgresTypeIdentifier dataType, @Nullable Object parameterValue) { if (dataType == null) { @@ -228,101 +296,33 @@ EncodedParameter encodeParameterValue(Object value, @Nullable PostgresTypeIdenti throw new IllegalArgumentException(String.format("Cannot encode parameter of type %s (%s)", value.getClass().getName(), parameterValue)); } - @SuppressWarnings({"unchecked", "rawtypes"}) - private static List> getDefaultCodecs(ByteBufAllocator byteBufAllocator, boolean preferAttachedBuffers, CodecConfiguration configuration) { - - List> codecs = new CopyOnWriteArrayList<>(Arrays.asList( - - // Prioritized Codecs - new StringCodec(byteBufAllocator), - new InstantCodec(byteBufAllocator, configuration::getZoneId), - new ZonedDateTimeCodec(byteBufAllocator), - new BinaryByteBufferCodec(byteBufAllocator), - new BinaryByteArrayCodec(byteBufAllocator), - - new BigDecimalCodec(byteBufAllocator), - new BigIntegerCodec(byteBufAllocator), - new BooleanCodec(byteBufAllocator), - new CharacterCodec(byteBufAllocator), - new DoubleCodec(byteBufAllocator), - new FloatCodec(byteBufAllocator), - new InetAddressCodec(byteBufAllocator), - new IntegerCodec(byteBufAllocator), - new IntervalCodec(byteBufAllocator), - new LocalDateCodec(byteBufAllocator), - new LocalDateTimeCodec(byteBufAllocator, configuration::getZoneId), - new LocalTimeCodec(byteBufAllocator), - new LongCodec(byteBufAllocator), - new OffsetDateTimeCodec(byteBufAllocator), - new OffsetTimeCodec(byteBufAllocator), - new ShortCodec(byteBufAllocator), - new UriCodec(byteBufAllocator), - new UrlCodec(byteBufAllocator), - new UuidCodec(byteBufAllocator), - new ZoneIdCodec(byteBufAllocator), - new DayOfWeekCodec(byteBufAllocator), - new MonthCodec(byteBufAllocator), - new MonthDayCodec(byteBufAllocator), - new PeriodCodec(byteBufAllocator), - new YearCodec(byteBufAllocator), - new YearMonthCodec(byteBufAllocator), - - // JSON - new JsonCodec(byteBufAllocator, preferAttachedBuffers), - new JsonByteArrayCodec(byteBufAllocator), - new JsonByteBufCodec(byteBufAllocator), - new JsonByteBufferCodec(byteBufAllocator), - new JsonInputStreamCodec(byteBufAllocator), - new JsonStringCodec(byteBufAllocator), - - // Fallback for Object.class - new ByteCodec(byteBufAllocator), - new DateCodec(byteBufAllocator, configuration::getZoneId), - - new BlobCodec(byteBufAllocator), - new ClobCodec(byteBufAllocator), - RefCursorCodec.INSTANCE, - RefCursorNameCodec.INSTANCE, - - // Array - new StringArrayCodec(byteBufAllocator), - - // Geometry - new CircleCodec(byteBufAllocator), - new PointCodec(byteBufAllocator), - new BoxCodec(byteBufAllocator), - new LineCodec(byteBufAllocator), - new LsegCodec(byteBufAllocator), - new PathCodec(byteBufAllocator), - new PolygonCodec(byteBufAllocator) - )); - - List> defaultArrayCodecs = new ArrayList<>(); + @Override + public EncodedParameter encodeNull(Class type) { + Assert.requireNonNull(type, "type must not be null"); - for (Codec codec : codecs) { + Codec codec = this.codecLookup.findEncodeNullCodec(type); + if (codec != null) { + return codec.encodeNull(); + } - if (codec instanceof ArrayCodecDelegate) { + throw new IllegalArgumentException(String.format("Cannot encode null parameter of type %s", type.getName())); + } - Assert.requireType(codec, AbstractCodec.class, "Codec " + codec + " must be a subclass of AbstractCodec to be registered as generic array codec"); - ArrayCodecDelegate delegate = (ArrayCodecDelegate) codec; - Class componentType = delegate.type(); + @Override + public Class preferredType(int dataType, Format format) { + Assert.requireNonNull(format, "format must not be null"); - if (codec instanceof BoxCodec) { - // BOX[] uses a ';' as a delimiter (i.e. "{(3.7,4.6),(1.9,2.8);(5,7),(1.5,3.3)}") - defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate.getArrayDataType(), delegate, componentType, (byte) ';')); - } else if (codec instanceof AbstractNumericCodec) { - defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.NUMERIC_ARRAY_TYPES)); - } else if (codec instanceof AbstractTemporalCodec) { - defaultArrayCodecs.add(new ConvertingArrayCodec(byteBufAllocator, delegate, componentType, ConvertingArrayCodec.DATE_ARRAY_TYPES)); - } else { - defaultArrayCodecs.add(new ArrayCodec(byteBufAllocator, delegate, componentType)); - } - } + Codec codec = this.codecLookup.findDecodeCodec(dataType, format, Object.class); + if (codec instanceof CodecMetadata) { + return ((CodecMetadata) codec).type(); } - codecs.addAll(defaultArrayCodecs); + return null; + } - return codecs; + @Override + public Iterator> iterator() { + return Collections.unmodifiableList(new ArrayList<>(this.codecs)).iterator(); } }