You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2024/11/17 13:30:12 UTC
(shardingsphere) branch master updated: Add TemporalParser (#33698)
This is an automated email from the ASF dual-hosted git repository.
zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 53fc0f7cdb8 Add TemporalParser (#33698)
53fc0f7cdb8 is described below
commit 53fc0f7cdb8196b90abdd9a419f44f4a5aed7c6d
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Sun Nov 17 21:30:06 2024 +0800
Add TemporalParser (#33698)
* Add TemporalParser
---
.../datetime/IntervalShardingAlgorithm.java | 279 +++------------------
.../datetime/temporal/TemporalHandler.java | 67 +++++
.../datetime/temporal/TemporalHandlerFactory.java | 62 +++++
.../temporal/type/LocalDateTemporalHandler.java | 52 ++++
.../type/LocalDateTimeTemporalHandler.java | 51 ++++
.../temporal/type/LocalTimeTemporalHandler.java | 52 ++++
.../temporal/type/MonthTemporalHandler.java | 58 +++++
.../temporal/type/YearMonthTemporalHandler.java | 51 ++++
.../temporal/type/YearTemporalHandler.java | 51 ++++
.../datetime/IntervalShardingAlgorithmTest.java | 3 +-
10 files changed, 484 insertions(+), 242 deletions(-)
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
index 2e7bb54dc07..deee7ca06dd 100644
--- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
@@ -22,6 +22,8 @@ import com.google.common.collect.Range;
import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandler;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandlerFactory;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
@@ -29,23 +31,15 @@ import org.apache.shardingsphere.sharding.exception.data.InvalidDatetimeFormatEx
import org.apache.shardingsphere.sharding.exception.data.NullShardingValueException;
import java.time.Instant;
-import java.time.LocalDate;
import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.Month;
-import java.time.Year;
-import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
-import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
-import java.time.temporal.TemporalQueries;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
-import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -133,230 +127,51 @@ public final class IntervalShardingAlgorithm implements StandardShardingAlgorith
@Override
public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Comparable<?>> shardingValue) {
ShardingSpherePreconditions.checkNotNull(shardingValue.getValue(), NullShardingValueException::new);
- return doSharding(availableTargetNames, Range.singleton(shardingValue.getValue())).stream().findFirst().orElse(null);
+ Range<Comparable<?>> range = Range.singleton(shardingValue.getValue());
+ return getMatchedTables(availableTargetNames, range).stream().findFirst().orElse(null);
}
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Comparable<?>> shardingValue) {
- return doSharding(availableTargetNames, shardingValue.getValueRange());
- }
-
- private Collection<String> doSharding(final Collection<String> availableTargetNames, final Range<Comparable<?>> range) {
- TemporalAccessor calculateTime = dateTimeLower;
- if (!calculateTime.isSupported(ChronoField.NANO_OF_DAY)) {
- if (calculateTime.isSupported(ChronoField.EPOCH_DAY)) {
- return doShardingInLocalDate(availableTargetNames, range, calculateTime);
- }
- if (calculateTime.isSupported(ChronoField.YEAR) && calculateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
- return doShardingInYearMonth(availableTargetNames, range, calculateTime);
- }
- if (calculateTime.isSupported(ChronoField.YEAR)) {
- return doShardingInYear(availableTargetNames, range, calculateTime);
- }
- if (calculateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
- return doShardingInMonth(availableTargetNames, range, calculateTime);
- }
- }
- if (!calculateTime.isSupported(ChronoField.EPOCH_DAY)) {
- return doShardingInLocalTime(availableTargetNames, range, calculateTime);
- }
- return doShardingInLocalDateTime(availableTargetNames, range, calculateTime);
- }
-
- private Collection<String> doShardingInLocalDateTime(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
- Set<String> result = new HashSet<>();
- LocalDateTime calculateTimeAsView = LocalDateTime.from(calculateTime);
- LocalDateTime dateTimeUpperAsLocalDateTime = LocalDateTime.from(dateTimeUpper);
- LocalDateTime dateTimeLowerAsLocalDateTime = LocalDateTime.from(dateTimeLower);
- while (!calculateTimeAsView.isAfter(dateTimeUpperAsLocalDateTime)) {
- if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount, stepUnit)), range, dateTimeLowerAsLocalDateTime, dateTimeUpperAsLocalDateTime)) {
- result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
- }
- calculateTimeAsView = calculateTimeAsView.plus(stepAmount, stepUnit);
- }
- return result;
- }
-
- private Collection<String> doShardingInLocalTime(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
- Set<String> result = new HashSet<>();
- LocalTime dateTimeUpperAsLocalTime = dateTimeUpper.query(TemporalQueries.localTime());
- LocalTime dateTimeLowerAsLocalTime = dateTimeLower.query(TemporalQueries.localTime());
- LocalTime calculateTimeAsView = calculateTime.query(TemporalQueries.localTime());
- while (!calculateTimeAsView.isAfter(dateTimeUpperAsLocalTime)) {
- if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount, stepUnit)), range, dateTimeLowerAsLocalTime, dateTimeUpperAsLocalTime)) {
- result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
- }
- calculateTimeAsView = calculateTimeAsView.plus(stepAmount, stepUnit);
- }
- return result;
- }
-
- private Collection<String> doShardingInLocalDate(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
- Set<String> result = new HashSet<>();
- LocalDate dateTimeUpperAsLocalDate = dateTimeUpper.query(TemporalQueries.localDate());
- LocalDate dateTimeLowerAsLocalDate = dateTimeLower.query(TemporalQueries.localDate());
- LocalDate calculateTimeAsView = calculateTime.query(TemporalQueries.localDate());
- while (!calculateTimeAsView.isAfter(dateTimeUpperAsLocalDate)) {
- if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount, stepUnit)), range, dateTimeLowerAsLocalDate, dateTimeUpperAsLocalDate)) {
- result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
+ return getMatchedTables(availableTargetNames, shardingValue.getValueRange());
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T extends TemporalAccessor & Comparable<?>> Collection<String> getMatchedTables(final Collection<String> availableTargetNames, final Range<Comparable<?>> range) {
+ Collection<String> result = new HashSet<>();
+ TemporalHandler<T> temporalHandler = TemporalHandlerFactory.newInstance(dateTimeLower);
+ T dateTimeUpper = temporalHandler.convertTo(this.dateTimeUpper);
+ T dateTimeLower = temporalHandler.convertTo(this.dateTimeLower);
+ T calculateTimeAsView = temporalHandler.convertTo(this.dateTimeLower);
+ while (!temporalHandler.isAfter(calculateTimeAsView, dateTimeUpper, stepAmount)) {
+ if (hasIntersection(Range.closedOpen(calculateTimeAsView, temporalHandler.add(calculateTimeAsView, stepAmount, stepUnit)), range, dateTimeLower, dateTimeUpper, temporalHandler)) {
+ result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames, temporalHandler));
}
- calculateTimeAsView = calculateTimeAsView.plus(stepAmount, stepUnit);
+ calculateTimeAsView = temporalHandler.add(calculateTimeAsView, stepAmount, stepUnit);
}
return result;
}
- private Collection<String> doShardingInYear(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
- Set<String> result = new HashSet<>();
- Year dateTimeUpperAsYear = dateTimeUpper.query(Year::from);
- Year dateTimeLowerAsYear = dateTimeLower.query(Year::from);
- Year calculateTimeAsView = calculateTime.query(Year::from);
- while (!calculateTimeAsView.isAfter(dateTimeUpperAsYear)) {
- if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount, stepUnit)), range, dateTimeLowerAsYear, dateTimeUpperAsYear)) {
- result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
- }
- calculateTimeAsView = calculateTimeAsView.plus(stepAmount, stepUnit);
- }
- return result;
+ private <T extends TemporalAccessor & Comparable<?>> Collection<String> getMatchedTables(final TemporalAccessor calculateTimeAsView,
+ final Collection<String> availableTargetNames, final TemporalHandler<T> temporalHandler) {
+ return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffixPattern.format(temporalHandler.convertTo(calculateTimeAsView)))).collect(Collectors.toSet());
}
- private Collection<String> doShardingInMonth(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
- Set<String> result = new HashSet<>();
- Month dateTimeUpperAsMonth = dateTimeUpper.query(Month::from);
- Month dateTimeLowerAsMonth = dateTimeLower.query(Month::from);
- Month calculateTimeAsView = calculateTime.query(Month::from);
- while (calculateTimeAsView.getValue() <= dateTimeUpperAsMonth.getValue() && (calculateTimeAsView.getValue() + stepAmount) <= Month.DECEMBER.getValue()) {
- if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount)), range, dateTimeLowerAsMonth, dateTimeUpperAsMonth)) {
- result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
- }
- calculateTimeAsView = calculateTimeAsView.plus(stepAmount);
- }
- return result;
- }
-
- private Collection<String> doShardingInYearMonth(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
- Set<String> result = new HashSet<>();
- YearMonth dateTimeUpperAsYearMonth = dateTimeUpper.query(YearMonth::from);
- YearMonth dateTimeLowerAsYearMonth = dateTimeLower.query(YearMonth::from);
- YearMonth calculateTimeAsView = calculateTime.query(YearMonth::from);
- while (!calculateTimeAsView.isAfter(dateTimeUpperAsYearMonth)) {
- if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount, stepUnit)), range, dateTimeLowerAsYearMonth, dateTimeUpperAsYearMonth)) {
- result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
- }
- calculateTimeAsView = calculateTimeAsView.plus(stepAmount, stepUnit);
- }
- return result;
- }
-
- private boolean hasIntersection(final Range<LocalDateTime> calculateRange, final Range<Comparable<?>> range, final LocalDateTime dateTimeLower, final LocalDateTime dateTimeUpper) {
- LocalDateTime lower = range.hasLowerBound() ? parseLocalDateTime(range.lowerEndpoint()) : dateTimeLower;
- LocalDateTime upper = range.hasUpperBound() ? parseLocalDateTime(range.upperEndpoint()) : dateTimeUpper;
+ private <T extends TemporalAccessor & Comparable<?>> boolean hasIntersection(final Range<T> calculateRange, final Range<Comparable<?>> range,
+ final T temporalLower, final T temporalUpper, final TemporalHandler<T> temporalHandler) {
+ T lower = range.hasLowerBound() ? parseTemporal(range.lowerEndpoint(), temporalHandler) : temporalLower;
+ T upper = range.hasUpperBound() ? parseTemporal(range.upperEndpoint(), temporalHandler) : temporalUpper;
BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
- Range<LocalDateTime> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
+ Range<T> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
}
- private boolean hasIntersection(final Range<LocalDate> calculateRange, final Range<Comparable<?>> range, final LocalDate dateTimeLower, final LocalDate dateTimeUpper) {
- LocalDate lower = range.hasLowerBound() ? parseLocalDate(range.lowerEndpoint()) : dateTimeLower;
- LocalDate upper = range.hasUpperBound() ? parseLocalDate(range.upperEndpoint()) : dateTimeUpper;
- BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
- BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
- Range<LocalDate> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
- return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
- }
-
- private boolean hasIntersection(final Range<LocalTime> calculateRange, final Range<Comparable<?>> range, final LocalTime dateTimeLower, final LocalTime dateTimeUpper) {
- LocalTime lower = range.hasLowerBound() ? parseLocalTime(range.lowerEndpoint()) : dateTimeLower;
- LocalTime upper = range.hasUpperBound() ? parseLocalTime(range.upperEndpoint()) : dateTimeUpper;
- BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
- BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
- Range<LocalTime> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
- return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
- }
-
- private boolean hasIntersection(final Range<Year> calculateRange, final Range<Comparable<?>> range, final Year dateTimeLower, final Year dateTimeUpper) {
- Year lower = range.hasLowerBound() ? parseYear(range.lowerEndpoint()) : dateTimeLower;
- Year upper = range.hasUpperBound() ? parseYear(range.upperEndpoint()) : dateTimeUpper;
- BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
- BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
- Range<Year> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
- return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
- }
-
- private boolean hasIntersection(final Range<Month> calculateRange, final Range<Comparable<?>> range, final Month dateTimeLower, final Month dateTimeUpper) {
- Month lower = range.hasLowerBound() ? parseMonth(range.lowerEndpoint()) : dateTimeLower;
- Month upper = range.hasUpperBound() ? parseMonth(range.upperEndpoint()) : dateTimeUpper;
- BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
- BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
- Range<Month> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
- return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
- }
-
- private boolean hasIntersection(final Range<YearMonth> calculateRange, final Range<Comparable<?>> range, final YearMonth dateTimeLower, final YearMonth dateTimeUpper) {
- YearMonth lower = range.hasLowerBound() ? parseYearMonth(range.lowerEndpoint()) : dateTimeLower;
- YearMonth upper = range.hasUpperBound() ? parseYearMonth(range.upperEndpoint()) : dateTimeUpper;
- BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
- BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
- Range<YearMonth> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
- return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
- }
-
- private LocalDateTime parseLocalDateTime(final Comparable<?> endpoint) {
- String dateTimeText = getDateTimeText(endpoint);
- return dateTimeText.length() >= dateTimePatternLength
- ? LocalDateTime.parse(dateTimeText.substring(0, dateTimePatternLength), dateTimeFormatter)
- : LocalDateTime.parse(dateTimeText, createRelaxedDateTimeFormatter(dateTimeText));
- }
-
- private LocalDate parseLocalDate(final Comparable<?> endpoint) {
- String dateTimeText = getDateTimeText(endpoint);
- return dateTimeText.length() >= dateTimePatternLength
- ? LocalDate.parse(dateTimeText.substring(0, dateTimePatternLength), dateTimeFormatter)
- : LocalDate.parse(dateTimeText, createRelaxedDateTimeFormatter(dateTimeText));
- }
-
- private LocalTime parseLocalTime(final Comparable<?> endpoint) {
- String dateTimeText = getDateTimeText(endpoint);
- return dateTimeText.length() >= dateTimePatternLength
- ? LocalTime.parse(dateTimeText.substring(0, dateTimePatternLength), dateTimeFormatter)
- : LocalTime.parse(dateTimeText, createRelaxedDateTimeFormatter(dateTimeText));
- }
-
- private Year parseYear(final Comparable<?> endpoint) {
+ private <T extends TemporalAccessor> T parseTemporal(final Comparable<?> endpoint, final TemporalHandler<T> temporalHandler) {
String dateTimeText = getDateTimeText(endpoint);
return dateTimeText.length() >= dateTimePatternLength
- ? Year.parse(dateTimeText.substring(0, dateTimePatternLength), dateTimeFormatter)
- : Year.parse(dateTimeText, createRelaxedDateTimeFormatter(dateTimeText));
- }
-
- private YearMonth parseYearMonth(final Comparable<?> endpoint) {
- String dateTimeText = getDateTimeText(endpoint);
- return dateTimeText.length() >= dateTimePatternLength
- ? YearMonth.parse(dateTimeText.substring(0, dateTimePatternLength), dateTimeFormatter)
- : YearMonth.parse(dateTimeText, createRelaxedDateTimeFormatter(dateTimeText));
- }
-
- /**
- * After the sharding key is formatted as a {@link String},
- * if the length of the {@link String} is less than `datetime-pattern`,
- * it usually means there is a problem with the sharding key.
- * @param endpoint A class carrying time information with an unknown class name.
- * @return {@link java.time.Month}
- */
- private Month parseMonth(final Comparable<?> endpoint) {
- return Month.of(Integer.parseInt(getDateTimeText(endpoint).substring(0, dateTimePatternLength)));
- }
-
- /**
- * When the sharding key is a {@link String} and the length of this {@link String} is less than the `datetime-pattern` set by the algorithm,
- * ShardingSphere will try to use a substring of `datetime-pattern` to parse the sharding key.
- * This is to be compatible with the behavior of ORM libraries such as <a href="https://github.com/go-gorm/gorm">go-gorm/gorm</a>.
- * @param dateTimeText Sharding key with class name {@link String}
- * @return Child `datetime-pattern`, the pattern length is consistent with the shard key.
- */
- private DateTimeFormatter createRelaxedDateTimeFormatter(final String dateTimeText) {
- String dateTimeFormatterString = dateTimePatternString.substring(0, dateTimeText.length());
- return DateTimeFormatter.ofPattern(dateTimeFormatterString);
+ ? temporalHandler.parse(dateTimeText.substring(0, dateTimePatternLength), dateTimeFormatter)
+ : temporalHandler.parse(dateTimeText, createRelaxedDateTimeFormatter(dateTimeText));
}
private String getDateTimeText(final Comparable<?> endpoint) {
@@ -375,32 +190,16 @@ public final class IntervalShardingAlgorithm implements StandardShardingAlgorith
return endpoint.toString();
}
- private Collection<String> getMatchedTables(final TemporalAccessor dateTime, final Collection<String> availableTargetNames) {
- String tableSuffix;
- if (!dateTime.isSupported(ChronoField.NANO_OF_DAY)) {
- if (dateTime.isSupported(ChronoField.EPOCH_DAY)) {
- tableSuffix = tableSuffixPattern.format(dateTime.query(TemporalQueries.localDate()));
- return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
- }
- if (dateTime.isSupported(ChronoField.YEAR) && dateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
- tableSuffix = tableSuffixPattern.format(dateTime.query(YearMonth::from));
- return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
- }
- if (dateTime.isSupported(ChronoField.YEAR)) {
- tableSuffix = tableSuffixPattern.format(dateTime.query(Year::from));
- return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
- }
- if (dateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
- tableSuffix = tableSuffixPattern.format(dateTime.query(Month::from));
- return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
- }
- }
- if (!dateTime.isSupported(ChronoField.EPOCH_DAY)) {
- tableSuffix = dateTime.query(TemporalQueries.localTime()).format(tableSuffixPattern);
- return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
- }
- tableSuffix = LocalDateTime.from(dateTime).format(tableSuffixPattern);
- return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
+ /*
+ * When the sharding key is a {@link String} and the length of this {@link String} is less than the `datetime-pattern` set by the algorithm, ShardingSphere will try to use a substring of
+ * `datetime-pattern` to parse the sharding key. This is to be compatible with the behavior of ORM libraries such as <a href="https://github.com/go-gorm/gorm">go-gorm/gorm</a>.
+ *
+ * @param dateTimeText Sharding key with class name {@link String}
+ *
+ * @return Child `datetime-pattern`, the pattern length is consistent with the shard key.
+ */
+ private DateTimeFormatter createRelaxedDateTimeFormatter(final String dateTimeText) {
+ return DateTimeFormatter.ofPattern(dateTimePatternString.substring(0, dateTimeText.length()));
}
@Override
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/TemporalHandler.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/TemporalHandler.java
new file mode 100644
index 00000000000..eba11286188
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/TemporalHandler.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal;
+
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Temporal handler.
+ *
+ * @param <T> type of temporal
+ */
+public interface TemporalHandler<T extends TemporalAccessor> {
+
+ /**
+ * Parse from text.
+ *
+ * @param text temporal text
+ * @param formatter date time formatter
+ * @return parsed temporal
+ */
+ T parse(CharSequence text, DateTimeFormatter formatter);
+
+ /**
+ * Convert temporal.
+ *
+ * @param temporal to be converted temporal
+ * @return converted temporal
+ */
+ T convertTo(TemporalAccessor temporal);
+
+ /**
+ * Judge whether temporal1 is after temporal2.
+ *
+ * @param temporal1 temporal1
+ * @param temporal2 temporal2
+ * @param stepAmount step amount
+ * @return is temporal1 after temporal2 or not
+ */
+ boolean isAfter(T temporal1, T temporal2, int stepAmount);
+
+ /**
+ * Add temporal.
+ *
+ * @param temporal to be added temporal
+ * @param stepAmount to be added step amount
+ * @param unit temporal unit
+ * @return added temporal
+ */
+ T add(T temporal, long stepAmount, TemporalUnit unit);
+}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/TemporalHandlerFactory.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/TemporalHandlerFactory.java
new file mode 100644
index 00000000000..48c09a5be08
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/TemporalHandlerFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type.LocalDateTemporalHandler;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type.LocalDateTimeTemporalHandler;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type.LocalTimeTemporalHandler;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type.MonthTemporalHandler;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type.YearMonthTemporalHandler;
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type.YearTemporalHandler;
+
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+
+/**
+ * Temporal handler factory.
+ */
+@NoArgsConstructor(access = AccessLevel.NONE)
+public final class TemporalHandlerFactory {
+
+ /**
+ * Create new instance of temporal handler.
+ *
+ * @param temporal temporal
+ * @return temporal handler
+ */
+ @SuppressWarnings("rawtypes")
+ public static TemporalHandler newInstance(final TemporalAccessor temporal) {
+ if (!temporal.isSupported(ChronoField.NANO_OF_DAY)) {
+ if (temporal.isSupported(ChronoField.EPOCH_DAY)) {
+ return new LocalDateTemporalHandler();
+ }
+ if (temporal.isSupported(ChronoField.YEAR) && temporal.isSupported(ChronoField.MONTH_OF_YEAR)) {
+ return new YearMonthTemporalHandler();
+ }
+ if (temporal.isSupported(ChronoField.YEAR)) {
+ return new YearTemporalHandler();
+ }
+ if (temporal.isSupported(ChronoField.MONTH_OF_YEAR)) {
+ return new MonthTemporalHandler();
+ }
+ }
+ return temporal.isSupported(ChronoField.EPOCH_DAY) ? new LocalDateTimeTemporalHandler() : new LocalTimeTemporalHandler();
+ }
+}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalDateTemporalHandler.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalDateTemporalHandler.java
new file mode 100644
index 00000000000..0035e27fc72
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalDateTemporalHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type;
+
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandler;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Local date temporal handler.
+ */
+public final class LocalDateTemporalHandler implements TemporalHandler<LocalDate> {
+
+ @Override
+ public LocalDate parse(final CharSequence text, final DateTimeFormatter formatter) {
+ return LocalDate.parse(text, formatter);
+ }
+
+ @Override
+ public LocalDate convertTo(final TemporalAccessor temporal) {
+ return temporal.query(TemporalQueries.localDate());
+ }
+
+ @Override
+ public boolean isAfter(final LocalDate temporal1, final LocalDate temporal2, final int stepAmount) {
+ return temporal1.isAfter(temporal2);
+ }
+
+ @Override
+ public LocalDate add(final LocalDate temporal, final long stepAmount, final TemporalUnit unit) {
+ return temporal.plus(stepAmount, unit);
+ }
+}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalDateTimeTemporalHandler.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalDateTimeTemporalHandler.java
new file mode 100644
index 00000000000..3fb9f45bd7a
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalDateTimeTemporalHandler.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type;
+
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandler;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Local date time temporal handler.
+ */
+public final class LocalDateTimeTemporalHandler implements TemporalHandler<LocalDateTime> {
+
+ @Override
+ public LocalDateTime parse(final CharSequence text, final DateTimeFormatter formatter) {
+ return LocalDateTime.parse(text, formatter);
+ }
+
+ @Override
+ public LocalDateTime convertTo(final TemporalAccessor temporal) {
+ return LocalDateTime.from(temporal);
+ }
+
+ @Override
+ public boolean isAfter(final LocalDateTime temporal1, final LocalDateTime temporal2, final int stepAmount) {
+ return temporal1.isAfter(temporal2);
+ }
+
+ @Override
+ public LocalDateTime add(final LocalDateTime temporal, final long stepAmount, final TemporalUnit unit) {
+ return temporal.plus(stepAmount, unit);
+ }
+}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalTimeTemporalHandler.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalTimeTemporalHandler.java
new file mode 100644
index 00000000000..c5671be9c17
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/LocalTimeTemporalHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type;
+
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandler;
+
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Local time temporal handler.
+ */
+public final class LocalTimeTemporalHandler implements TemporalHandler<LocalTime> {
+
+ @Override
+ public LocalTime parse(final CharSequence text, final DateTimeFormatter formatter) {
+ return LocalTime.parse(text, formatter);
+ }
+
+ @Override
+ public LocalTime convertTo(final TemporalAccessor temporal) {
+ return temporal.query(TemporalQueries.localTime());
+ }
+
+ @Override
+ public boolean isAfter(final LocalTime temporal1, final LocalTime temporal2, final int stepAmount) {
+ return temporal1.isAfter(temporal2);
+ }
+
+ @Override
+ public LocalTime add(final LocalTime temporal, final long stepAmount, final TemporalUnit unit) {
+ return temporal.plus(stepAmount, unit);
+ }
+}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/MonthTemporalHandler.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/MonthTemporalHandler.java
new file mode 100644
index 00000000000..b05e5ed524c
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/MonthTemporalHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type;
+
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandler;
+
+import java.time.Month;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Month temporal handler.
+ */
+public final class MonthTemporalHandler implements TemporalHandler<Month> {
+
+ /*
+ * After the sharding key is formatted as a {@link String}, if the length of the {@link String} is less than `datetime-pattern`, it usually means there is a problem with the sharding key.
+ *
+ * @param endpoint A class carrying time information with an unknown class name.
+ *
+ * @return {@link java.time.Month}
+ */
+ @Override
+ public Month parse(final CharSequence text, final DateTimeFormatter formatter) {
+ return Month.of(Integer.parseInt(text.toString()));
+ }
+
+ @Override
+ public Month convertTo(final TemporalAccessor temporal) {
+ return Month.from(temporal);
+ }
+
+ @Override
+ public boolean isAfter(final Month temporal1, final Month temporal2, final int stepAmount) {
+ return temporal1.getValue() > temporal2.getValue() || (temporal1.getValue() + stepAmount) > Month.DECEMBER.getValue();
+ }
+
+ @Override
+ public Month add(final Month temporal, final long stepAmount, final TemporalUnit unit) {
+ return temporal.plus(stepAmount);
+ }
+}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/YearMonthTemporalHandler.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/YearMonthTemporalHandler.java
new file mode 100644
index 00000000000..04f750d9a5d
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/YearMonthTemporalHandler.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type;
+
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandler;
+
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Year month temporal handler.
+ */
+public final class YearMonthTemporalHandler implements TemporalHandler<YearMonth> {
+
+ @Override
+ public YearMonth parse(final CharSequence text, final DateTimeFormatter formatter) {
+ return YearMonth.parse(text, formatter);
+ }
+
+ @Override
+ public YearMonth convertTo(final TemporalAccessor temporal) {
+ return temporal.query(YearMonth::from);
+ }
+
+ @Override
+ public boolean isAfter(final YearMonth temporal1, final YearMonth temporal2, final int stepAmount) {
+ return temporal1.isAfter(temporal2);
+ }
+
+ @Override
+ public YearMonth add(final YearMonth temporal, final long stepAmount, final TemporalUnit unit) {
+ return temporal.plus(stepAmount, unit);
+ }
+}
diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/YearTemporalHandler.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/YearTemporalHandler.java
new file mode 100644
index 00000000000..b8116388db0
--- /dev/null
+++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/temporal/type/YearTemporalHandler.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.type;
+
+import org.apache.shardingsphere.sharding.algorithm.sharding.datetime.temporal.TemporalHandler;
+
+import java.time.Year;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Year temporal handler.
+ */
+public final class YearTemporalHandler implements TemporalHandler<Year> {
+
+ @Override
+ public Year parse(final CharSequence text, final DateTimeFormatter formatter) {
+ return Year.parse(text, formatter);
+ }
+
+ @Override
+ public Year convertTo(final TemporalAccessor temporal) {
+ return Year.from(temporal);
+ }
+
+ @Override
+ public boolean isAfter(final Year temporal1, final Year temporal2, final int stepAmount) {
+ return temporal1.isAfter(temporal2);
+ }
+
+ @Override
+ public Year add(final Year temporal, final long stepAmount, final TemporalUnit unit) {
+ return temporal.plus(stepAmount, unit);
+ }
+}
diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
index 64c2cd8575e..169ba0f807d 100644
--- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
+++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
@@ -130,8 +130,7 @@ class IntervalShardingAlgorithmTest {
@Test
void assertRangeDoShardingByQuarter() {
- Collection<String> actual = shardingAlgorithmByQuarter.doSharding(availableTablesForQuarterDataSources,
- createShardingValue("2019-10-15 10:59:08", "2020-04-08 10:59:08"));
+ Collection<String> actual = shardingAlgorithmByQuarter.doSharding(availableTablesForQuarterDataSources, createShardingValue("2019-10-15 10:59:08", "2020-04-08 10:59:08"));
assertThat(actual.size(), is(3));
}