Skip to content

Commit

Permalink
Create new ValuesException
Browse files Browse the repository at this point in the history
Split test with different causes of exception
Wrap Java methods throwing DateTimeException
Change some exception types
  • Loading branch information
Lojjs committed Apr 5, 2018
1 parent 52b75b3 commit 6d323f7
Show file tree
Hide file tree
Showing 16 changed files with 469 additions and 268 deletions.
Expand Up @@ -21,7 +21,7 @@ package org.neo4j.cypher

import org.neo4j.cypher.internal.util.v3_4.spi.MapToPublicExceptions
import org.neo4j.cypher.internal.util.v3_4.{CypherException => InternalCypherException}
import org.neo4j.values.utils.{UnsupportedTemporalUnitException, ValuesException}
import org.neo4j.values.utils.{InvalidTemporalArgumentException, TemporalParseException, UnsupportedTemporalUnitException, ValuesException}

object exceptionHandler extends MapToPublicExceptions[CypherException] {
override def syntaxException(message: String, query: String, offset: Option[Int], cause: Throwable) = new SyntaxException(message, query, offset, cause)
Expand Down Expand Up @@ -110,6 +110,15 @@ object exceptionHandler extends MapToPublicExceptions[CypherException] {
exception match {
case e: UnsupportedTemporalUnitException =>
exceptionHandler.cypherTypeException(e.getMessage, e)
case e: InvalidTemporalArgumentException =>
exceptionHandler.invalidArgumentException(e.getMessage, e)
case e: TemporalParseException =>
if (e.getParsedData == null) {
exceptionHandler.syntaxException(e.getMessage, "", null, e)
}
else {
exceptionHandler.syntaxException(e.getMessage, e.getParsedData, Option(e.getErrorIndex), e)
}
}
}
}
Expand Up @@ -31,10 +31,12 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalUnit;
import java.time.zone.ZoneRulesException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
Expand All @@ -45,6 +47,9 @@
import org.neo4j.values.AnyValue;
import org.neo4j.values.StructureBuilder;
import org.neo4j.values.ValueMapper;
import org.neo4j.values.utils.InvalidTemporalArgumentException;
import org.neo4j.values.utils.TemporalParseException;
import org.neo4j.values.utils.UnsupportedTemporalUnitException;
import org.neo4j.values.virtual.MapValue;
import org.neo4j.values.virtual.VirtualValues;

Expand Down Expand Up @@ -85,12 +90,12 @@ public static DateTimeValue datetime(
public static DateTimeValue datetime(
int year, int month, int day, int hour, int minute, int second, int nanoOfSecond, ZoneId zone )
{
return new DateTimeValue( ZonedDateTime.of( year, month, day, hour, minute, second, nanoOfSecond, zone ) );
return new DateTimeValue( assertValidArgument( () -> ZonedDateTime.of( year, month, day, hour, minute, second, nanoOfSecond, zone ) ) );
}

public static DateTimeValue datetime( long epochSecond, long nano, ZoneOffset zoneOffset )
{
return new DateTimeValue( ofInstant( ofEpochSecond( epochSecond, nano ), zoneOffset ) );
return new DateTimeValue( assertValidArgument( () -> ofInstant( ofEpochSecond( epochSecond, nano ), zoneOffset ) ) );
}

public static DateTimeValue datetime( ZonedDateTime datetime )
Expand All @@ -105,22 +110,22 @@ public static DateTimeValue datetime( OffsetDateTime datetime )

public static DateTimeValue datetime( long epochSecondUTC, long nano, ZoneId zone )
{
return new DateTimeValue( ofInstant( ofEpochSecond( epochSecondUTC, nano ), zone ) );
return new DateTimeValue( assertValidArgument( () -> ofInstant( ofEpochSecond( epochSecondUTC, nano ), zone ) ) );
}

public static DateTimeValue ofEpoch( IntegralValue epochSecondUTC, IntegralValue nano )
{
long ns = safeCastIntegral( "nanosecond", nano, 0 );
if ( ns < 0 || ns >= 1000_000_000 )
{
throw new IllegalArgumentException( "Invalid nanosecond: " + ns );
throw new InvalidTemporalArgumentException( "Invalid nanosecond: " + ns );
}
return new DateTimeValue( ofInstant( ofEpochSecond( epochSecondUTC.longValue(), ns ), UTC ) );
return new DateTimeValue( assertValidArgument( () -> ofInstant( ofEpochSecond( epochSecondUTC.longValue(), ns ), UTC ) ) );
}

public static DateTimeValue ofEpochMillis( IntegralValue millisUTC )
{
return new DateTimeValue( ofInstant( ofEpochMilli( millisUTC.longValue() ), UTC ) );
return new DateTimeValue( assertValidArgument( () -> ofInstant( ofEpochMilli( millisUTC.longValue() ), UTC ) ) );
}

public static DateTimeValue parse( CharSequence text, Supplier<ZoneId> defaultZone, CSVHeaderInformation fieldsFromHeader )
Expand All @@ -129,7 +134,7 @@ public static DateTimeValue parse( CharSequence text, Supplier<ZoneId> defaultZo
{
if ( !(fieldsFromHeader instanceof TimeCSVHeaderInformation) )
{
throw new IllegalStateException( "Wrong header information type: " + fieldsFromHeader );
throw new TemporalParseException( "Wrong header information type: " + fieldsFromHeader );
}
// Override defaultZone
defaultZone = ((TimeCSVHeaderInformation) fieldsFromHeader).zoneSupplier( defaultZone );
Expand Down Expand Up @@ -245,7 +250,7 @@ public DateTimeValue buildInternal()
AnyValue dtField = fields.get( Field.datetime );
if ( !(dtField instanceof TemporalValue) )
{
throw new IllegalArgumentException( String.format( "Cannot construct date time from: %s", dtField ) );
throw new InvalidTemporalArgumentException( String.format( "Cannot construct date time from: %s", dtField ) );
}
TemporalValue dt = (TemporalValue) dtField;
LocalTime timePart = dt.getTimePart( defaultZone ).toLocalTime();
Expand All @@ -260,20 +265,20 @@ else if ( selectingEpoch )
AnyValue epochField = fields.get( Field.epochSeconds );
if ( !(epochField instanceof IntegralValue) )
{
throw new IllegalArgumentException( String.format( "Cannot construct date time from: %s", epochField ) );
throw new InvalidTemporalArgumentException( String.format( "Cannot construct date time from: %s", epochField ) );
}
IntegralValue epochSeconds = (IntegralValue) epochField;
result = ZonedDateTime.ofInstant( Instant.ofEpochMilli( epochSeconds.longValue() * 1000 ), timezone() );
result = assertValidArgument( () -> ZonedDateTime.ofInstant( Instant.ofEpochMilli( epochSeconds.longValue() * 1000 ), timezone() ) );
}
else
{
AnyValue epochField = fields.get( Field.epochMillis );
if ( !(epochField instanceof IntegralValue) )
{
throw new IllegalArgumentException( String.format( "Cannot construct date time from: %s", epochField ) );
throw new InvalidTemporalArgumentException( String.format( "Cannot construct date time from: %s", epochField ) );
}
IntegralValue epochMillis = (IntegralValue) epochField;
result = ZonedDateTime.ofInstant( Instant.ofEpochMilli( epochMillis.longValue() ), timezone() );
result = assertValidArgument( () -> ZonedDateTime.ofInstant( Instant.ofEpochMilli( epochMillis.longValue() ), timezone() ) );
}
selectingTimeZone = false;
}
Expand All @@ -287,7 +292,7 @@ else if ( selectingTime || selectingDate )
AnyValue timeField = fields.get( Field.time );
if ( !(timeField instanceof TemporalValue) )
{
throw new IllegalArgumentException( String.format( "Cannot construct time from: %s", timeField ) );
throw new InvalidTemporalArgumentException( String.format( "Cannot construct time from: %s", timeField ) );
}
TemporalValue t = (TemporalValue) timeField;
time = t.getTimePart( defaultZone ).toLocalTime();
Expand All @@ -306,7 +311,7 @@ else if ( selectingTime || selectingDate )
AnyValue dateField = fields.get( Field.date );
if ( !(dateField instanceof TemporalValue) )
{
throw new IllegalArgumentException( String.format( "Cannot construct date from: %s", dateField ) );
throw new InvalidTemporalArgumentException( String.format( "Cannot construct date from: %s", dateField ) );
}
TemporalValue t = (TemporalValue) dateField;
date = t.getDatePart();
Expand Down Expand Up @@ -338,7 +343,14 @@ else if ( selectingTime || selectingDate )
{
if ( ((selectingTime || selectingDateTime) && selectingTimeZone) || selectingEpoch )
{
result = result.withZoneSameInstant( timezone() );
try
{
result = result.withZoneSameInstant( timezone() );
}
catch ( DateTimeParseException e )
{
throw new InvalidTemporalArgumentException( e.getMessage(), e );
}
}
else
{
Expand All @@ -363,7 +375,7 @@ protected DateTimeValue selectDateTime( AnyValue datetime )
return new DateTimeValue( ZonedDateTime.of(
((LocalDateTimeValue) datetime).temporal(), timezone() ) );
}
throw new IllegalArgumentException( "Cannot select datetime from: " + datetime );
throw new UnsupportedTemporalUnitException( "Cannot select datetime from: " + datetime );
}
};
}
Expand Down Expand Up @@ -579,10 +591,18 @@ private static DateTimeValue parse( Matcher matcher, Supplier<ZoneId> defaultZon
zone = parseZoneName( zoneName );
if ( offset != null )
{
ZoneOffset expected = zone.getRules().getOffset( local );
ZoneOffset expected;
try
{
expected = zone.getRules().getOffset( local );
}
catch ( ZoneRulesException e )
{
throw new TemporalParseException( e.getMessage(), e );
}
if ( !expected.equals( offset ) )
{
throw new IllegalArgumentException( "Timezone and offset do not match: " + matcher.group() );
throw new InvalidTemporalArgumentException( "Timezone and offset do not match: " + matcher.group() );
}
}
}
Expand All @@ -599,7 +619,16 @@ else if ( offset != null )

static ZoneId parseZoneName( String zoneName )
{
return ZONE_NAME_PARSER.parse( zoneName.replace( ' ', '_' ) ).query( TemporalQueries.zoneId() );
ZoneId parsedName;
try
{
parsedName = ZONE_NAME_PARSER.parse( zoneName.replace( ' ', '_' ) ).query( TemporalQueries.zoneId() );
}
catch ( DateTimeParseException e)
{
throw new TemporalParseException( e.getMessage(), e.getParsedString(), e.getErrorIndex(), e );
}
return parsedName;
}

abstract static class DateTimeBuilder<Result> extends Builder<Result>
Expand Down
Expand Up @@ -33,14 +33,15 @@
import java.time.temporal.IsoFields;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.neo4j.helpers.collection.Pair;
import org.neo4j.values.StructureBuilder;
import org.neo4j.values.ValueMapper;
import org.neo4j.values.utils.InvalidTemporalArgumentException;
import org.neo4j.values.utils.TemporalParseException;
import org.neo4j.values.utils.UnsupportedTemporalUnitException;
import org.neo4j.values.virtual.MapValue;
import org.neo4j.values.virtual.VirtualValues;
Expand All @@ -63,27 +64,27 @@ public static DateValue date( LocalDate value )

public static DateValue date( int year, int month, int day )
{
return new DateValue( LocalDate.of( year, month, day ) );
return new DateValue( assertValidArgument( () -> LocalDate.of( year, month, day ) ) );
}

public static DateValue weekDate( int year, int week, int dayOfWeek )
{
return new DateValue( localWeekDate( year, week, dayOfWeek ) );
return new DateValue( assertValidArgument( () -> localWeekDate( year, week, dayOfWeek ) ) );
}

public static DateValue quarterDate( int year, int quarter, int dayOfQuarter )
{
return new DateValue( localQuarterDate( year, quarter, dayOfQuarter ) );
return new DateValue( assertValidArgument( () -> localQuarterDate( year, quarter, dayOfQuarter ) ) );
}

public static DateValue ordinalDate( int year, int dayOfYear )
{
return new DateValue( LocalDate.ofYearDay( year, dayOfYear ) );
return new DateValue( assertValidArgument( () -> LocalDate.ofYearDay( year, dayOfYear ) ) );
}

public static DateValue epochDate( long epochDay )
{
return new DateValue( LocalDate.ofEpochDay( epochDay ) );
return new DateValue( assertValidArgument( () -> LocalDate.ofEpochDay( epochDay ) ) );
}

public static DateValue parse( CharSequence text )
Expand Down Expand Up @@ -213,13 +214,13 @@ LocalDate getDatePart()
@Override
LocalTime getLocalTimePart()
{
throw new IllegalArgumentException( String.format( "Cannot get the time of: %s", this ) );
throw new UnsupportedTemporalUnitException( String.format( "Cannot get the time of: %s", this ) );
}

@Override
OffsetTime getTimePart( Supplier<ZoneId> defaultZone )
{
throw new IllegalArgumentException( String.format( "Cannot get the time of: %s", this ) );
throw new UnsupportedTemporalUnitException( String.format( "Cannot get the time of: %s", this ) );
}

@Override
Expand Down Expand Up @@ -410,24 +411,24 @@ private static LocalDate parse(
String month = matcher.group( MONTH );
if ( month != null )
{
return LocalDate.of( year, parseInt( month ), optInt( matcher.group( DAY ) ) );
return assertParsable( () -> LocalDate.of( year, parseInt( month ), optInt( matcher.group( DAY ) ) ) );
}
String week = matcher.group( WEEK );
if ( week != null )
{
return localWeekDate( year, parseInt( week ), optInt( matcher.group( DOW ) ) );
return assertParsable( () -> localWeekDate( year, parseInt( week ), optInt( matcher.group( DOW ) ) ) );
}
String quarter = matcher.group( QUARTER );
if ( quarter != null )
{
return localQuarterDate( year, parseInt( quarter ), optInt( matcher.group( DOQ ) ) );
return assertParsable( () -> localQuarterDate( year, parseInt( quarter ), optInt( matcher.group( DOQ ) ) ) );
}
String doy = matcher.group( DOY );
if ( doy != null )
{
return LocalDate.ofYearDay( year, parseInt( doy ) );
return assertParsable( () -> LocalDate.ofYearDay( year, parseInt( doy ) ) );
}
return LocalDate.of( year, 1, 1 );
return assertParsable( () -> LocalDate.of( year, 1, 1 ) );
}

private static DateValue parse( Matcher matcher )
Expand All @@ -448,7 +449,7 @@ private static LocalDate localWeekDate( int year, int week, int dayOfWeek )
// week 53 of years that don't have 53 weeks, so we have to guard for this:
if ( week == 53 && withWeek.get( IsoFields.WEEK_BASED_YEAR ) != year )
{
throw new DateTimeException( String.format( "Year %d does not contain %d weeks.", year, week ) );
throw new InvalidTemporalArgumentException( String.format( "Year %d does not contain %d weeks.", year, week ) );
}
return withWeek.with( ChronoField.DAY_OF_WEEK, dayOfWeek );
}
Expand All @@ -458,13 +459,13 @@ private static LocalDate localQuarterDate( int year, int quarter, int dayOfQuart
// special handling for the range of Q1 and Q2, since they are shorter than Q3 and Q4
if ( quarter == 2 && dayOfQuarter == 92 )
{
throw new DateTimeException( "Quarter 2 only has 91 days." );
throw new InvalidTemporalArgumentException( "Quarter 2 only has 91 days." );
}
// instantiate the yearDate now, because we use it to know if it is a leap year
LocalDate yearDate = LocalDate.ofYearDay( year, dayOfQuarter ); // guess on the day
if ( quarter == 1 && dayOfQuarter > 90 && (!yearDate.isLeapYear() || dayOfQuarter == 92) )
{
throw new DateTimeException( String.format(
throw new InvalidTemporalArgumentException( String.format(
"Quarter 1 of %d only has %d days.", year, yearDate.isLeapYear() ? 91 : 90 ) );
}
return yearDate
Expand Down Expand Up @@ -512,7 +513,7 @@ private LocalDate getDateOf( org.neo4j.values.AnyValue temporal )
TemporalValue v = (TemporalValue) temporal;
return v.getDatePart();
}
throw new IllegalArgumentException( String.format( "Cannot construct date from: %s", temporal ) );
throw new InvalidTemporalArgumentException( String.format( "Cannot construct date from: %s", temporal ) );
}

@Override
Expand Down

0 comments on commit 6d323f7

Please sign in to comment.