SOLR-10303: Supporting more datatypes via a TemporalAccessor

This commit is contained in:
Gethin James 2017-03-20 17:02:41 +01:00 committed by Joel Bernstein
parent cf14b4be03
commit c6fbb27376
2 changed files with 74 additions and 35 deletions

View File

@ -22,7 +22,10 @@ import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields; import java.time.temporal.IsoFields;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
@ -62,7 +65,7 @@ public class DatePartEvaluator extends NumberEvaluator {
public Number evaluate(Tuple tuple) throws IOException { public Number evaluate(Tuple tuple) throws IOException {
Instant instant = null; Instant instant = null;
LocalDateTime date = null; TemporalAccessor date = null;
//First evaluate the parameter //First evaluate the parameter
StreamEvaluator streamEvaluator = subEvaluators.get(0); StreamEvaluator streamEvaluator = subEvaluators.get(0);
@ -76,8 +79,8 @@ public class DatePartEvaluator extends NumberEvaluator {
instant = (Instant) tupleValue; instant = (Instant) tupleValue;
} else if (tupleValue instanceof Date) { } else if (tupleValue instanceof Date) {
instant = ((Date) tupleValue).toInstant(); instant = ((Date) tupleValue).toInstant();
} else if (tupleValue instanceof LocalDateTime) { } else if (tupleValue instanceof TemporalAccessor) {
date = ((LocalDateTime) tupleValue); date = ((TemporalAccessor) tupleValue);
} }
if (instant != null) { if (instant != null) {
@ -110,22 +113,23 @@ public class DatePartEvaluator extends NumberEvaluator {
* @param date * @param date
* @return the evaluated value * @return the evaluated value
*/ */
private Number evaluate(LocalDateTime date) throws IOException { private Number evaluate(TemporalAccessor date) throws IOException {
try {
switch (function) { switch (function) {
case year: case year:
return date.getYear(); return date.get(ChronoField.YEAR);
case month: case month:
return date.getMonthValue(); return date.get(ChronoField.MONTH_OF_YEAR);
case day: case day:
return date.getDayOfMonth(); return date.get(ChronoField.DAY_OF_MONTH);
case dayofyear: case dayofyear:
return date.getDayOfYear(); return date.get(ChronoField.DAY_OF_YEAR);
case hour: case hour:
return date.getHour(); return date.get(ChronoField.HOUR_OF_DAY);
case minute: case minute:
return date.getMinute(); return date.get(ChronoField.MINUTE_OF_HOUR);
case second: case second:
return date.getSecond(); return date.get(ChronoField.SECOND_OF_MINUTE);
case dayofquarter: case dayofquarter:
return date.get(IsoFields.DAY_OF_QUARTER); return date.get(IsoFields.DAY_OF_QUARTER);
case quarter: case quarter:
@ -133,9 +137,14 @@ public class DatePartEvaluator extends NumberEvaluator {
case week: case week:
return date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); return date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
case epoch: case epoch:
return date.atZone(ZoneOffset.UTC).toInstant().toEpochMilli(); if (date instanceof LocalDateTime) {
return ((LocalDateTime)date).atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
} }
throw new IOException(String.format(Locale.ROOT, "Unsupported function %s called on LocalDateTime %s", function, date.toString())); }
} catch (UnsupportedTemporalTypeException utte) {
throw new IOException(String.format(Locale.ROOT, "It is not possible to call '%s' function on %s", function, date.getClass().getName()));
}
throw new IOException(String.format(Locale.ROOT, "Unsupported function '%s' called on %s", function, date.toString()));
} }
@Override @Override

View File

@ -20,6 +20,8 @@ package org.apache.solr.client.solrj.io.stream.eval;
import java.io.IOException; import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.MonthDay;
import java.time.YearMonth;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -72,7 +74,7 @@ public class DatePartEvaluatorTest {
evaluator = factory.constructEvaluator("nope(a)"); evaluator = factory.constructEvaluator("nope(a)");
evaluator.evaluate(new Tuple(null)); evaluator.evaluate(new Tuple(null));
assertTrue(false); assertTrue(false);
} catch (Exception e) { } catch (IOException e) {
assertTrue(e.getCause().getCause().getMessage().contains("Invalid date expression nope")); assertTrue(e.getCause().getCause().getMessage().contains("Invalid date expression nope"));
assertTrue(e.getCause().getCause().getMessage().contains("expecting one of [year, month, day")); assertTrue(e.getCause().getCause().getMessage().contains("expecting one of [year, month, day"));
} }
@ -80,21 +82,21 @@ public class DatePartEvaluatorTest {
try { try {
evaluator = factory.constructEvaluator("week()"); evaluator = factory.constructEvaluator("week()");
assertTrue(false); assertTrue(false);
} catch (Exception e) { } catch (IOException e) {
assertTrue(e.getCause().getCause().getMessage().contains("Invalid expression week()")); assertTrue(e.getCause().getCause().getMessage().contains("Invalid expression week()"));
} }
try { try {
evaluator = factory.constructEvaluator("week(a, b)"); evaluator = factory.constructEvaluator("week(a, b)");
assertTrue(false); assertTrue(false);
} catch (Exception e) { } catch (IOException e) {
assertTrue(e.getCause().getCause().getMessage().contains("expecting one value but found 2")); assertTrue(e.getCause().getCause().getMessage().contains("expecting one value but found 2"));
} }
try { try {
evaluator = factory.constructEvaluator("Week()"); evaluator = factory.constructEvaluator("Week()");
assertTrue(false); assertTrue(false);
} catch (Exception e) { } catch (IOException e) {
assertTrue(e.getMessage().contains("Invalid evaluator expression Week() - function 'Week' is unknown")); assertTrue(e.getMessage().contains("Invalid evaluator expression Week() - function 'Week' is unknown"));
} }
} }
@ -109,7 +111,7 @@ public class DatePartEvaluatorTest {
values.put("a", 12); values.put("a", 12);
Object result = evaluator.evaluate(new Tuple(values)); Object result = evaluator.evaluate(new Tuple(values));
assertTrue(false); assertTrue(false);
} catch (Exception e) { } catch (IOException e) {
assertEquals("Invalid parameter 12 - The parameter must be a string formatted ISO_INSTANT or of type Instant,Date or LocalDateTime.", e.getMessage()); assertEquals("Invalid parameter 12 - The parameter must be a string formatted ISO_INSTANT or of type Instant,Date or LocalDateTime.", e.getMessage());
} }
@ -118,7 +120,7 @@ public class DatePartEvaluatorTest {
values.put("a", "1995-12-31"); values.put("a", "1995-12-31");
Object result = evaluator.evaluate(new Tuple(values)); Object result = evaluator.evaluate(new Tuple(values));
assertTrue(false); assertTrue(false);
} catch (Exception e) { } catch (IOException e) {
assertEquals("Invalid parameter 1995-12-31 - The String must be formatted in the ISO_INSTANT date format.", e.getMessage()); assertEquals("Invalid parameter 1995-12-31 - The String must be formatted in the ISO_INSTANT date format.", e.getMessage());
} }
@ -127,7 +129,7 @@ public class DatePartEvaluatorTest {
values.put("a", ""); values.put("a", "");
Object result = evaluator.evaluate(new Tuple(values)); Object result = evaluator.evaluate(new Tuple(values));
assertTrue(false); assertTrue(false);
} catch (Exception e) { } catch (IOException e) {
assertEquals("Invalid parameter - The parameter must be a string formatted ISO_INSTANT or of type Instant,Date or LocalDateTime.", e.getMessage()); assertEquals("Invalid parameter - The parameter must be a string formatted ISO_INSTANT or of type Instant,Date or LocalDateTime.", e.getMessage());
} }
@ -220,6 +222,34 @@ public class DatePartEvaluatorTest {
testFunction("epoch(a)", localDateTime, aDate.getTime()); testFunction("epoch(a)", localDateTime, aDate.getTime());
} }
@Test
public void testLimitedFunctions() throws Exception {
MonthDay monthDay = MonthDay.of(12,5);
testFunction("month(a)", monthDay, 12);
testFunction("day(a)", monthDay, 5);
try {
testFunction("year(a)", monthDay, 2017);
assertTrue(false);
} catch (IOException e) {
assertEquals("It is not possible to call 'year' function on java.time.MonthDay", e.getMessage());
}
YearMonth yearMonth = YearMonth.of(2018, 4);
testFunction("month(a)", yearMonth, 4);
testFunction("year(a)", yearMonth, 2018);
try {
testFunction("day(a)", yearMonth, 5);
assertTrue(false);
} catch (IOException e) {
assertEquals("It is not possible to call 'day' function on java.time.YearMonth", e.getMessage());
}
}
public void testFunction(String expression, Object value, Number expected) throws Exception { public void testFunction(String expression, Object value, Number expected) throws Exception {
StreamEvaluator evaluator = factory.constructEvaluator(expression); StreamEvaluator evaluator = factory.constructEvaluator(expression);
values.clear(); values.clear();