Skip to content

Commit

Permalink
Merge pull request #11136 from Lojjs/3.4-temporal-accessors
Browse files Browse the repository at this point in the history
Temporal accessors.
  • Loading branch information
craigtaverner committed Mar 6, 2018
2 parents bd93d1f + f23f38b commit c109b71
Show file tree
Hide file tree
Showing 17 changed files with 295 additions and 43 deletions.
Expand Up @@ -25,8 +25,8 @@ import org.neo4j.cypher.internal.runtime.interpreted.commands.values.KeyToken
import org.neo4j.cypher.internal.runtime.interpreted.IsMap
import org.neo4j.cypher.internal.runtime.interpreted.pipes.QueryState
import org.neo4j.values.AnyValue
import org.neo4j.values.storable.Values
import org.neo4j.values.virtual.{VirtualRelationshipValue, VirtualNodeValue}
import org.neo4j.values.storable.{DurationValue, TemporalValue, Values}
import org.neo4j.values.virtual.{VirtualNodeValue, VirtualRelationshipValue}

case class Property(mapExpr: Expression, propertyKey: KeyToken)
extends Expression with Product with Serializable
Expand All @@ -44,6 +44,8 @@ case class Property(mapExpr: Expression, propertyKey: KeyToken)
case Some(propId) => state.query.relationshipOps.getProperty(r.id(), propId)
}
case IsMap(mapFunc) => mapFunc(state.query).get(propertyKey.name)
case t: TemporalValue[_,_] => t.get(propertyKey.name)
case d: DurationValue => d.get(propertyKey.name)
case other => throw new CypherTypeException(s"Type mismatch: expected a map but was $other")
}

Expand Down
Expand Up @@ -377,6 +377,18 @@ ZoneId getZoneId( Supplier<ZoneId> defaultZone )
return value.getZone();
}

@Override
ZoneId getZoneId()
{
return value.getZone();
}

@Override
ZoneOffset getZoneOffset()
{
return value.getOffset();
}

@Override
public boolean hasTimeZone()
{
Expand Down
Expand Up @@ -26,6 +26,7 @@
import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
Expand Down Expand Up @@ -216,7 +217,19 @@ OffsetTime getTimePart( Supplier<ZoneId> defaultZone )
@Override
ZoneId getZoneId( Supplier<ZoneId> defaultZone )
{
throw new IllegalArgumentException( String.format( "Cannot get the time zone of: %s", this ) );
throw new UnsupportedTemporalTypeException( String.format( "Cannot get the time zone of: %s", this ) );
}

@Override
ZoneId getZoneId()
{
throw new UnsupportedTemporalTypeException( "Cannot get the timezone of" + this );
}

@Override
ZoneOffset getZoneOffset()
{
throw new UnsupportedTemporalTypeException( "Cannot get the offset of" + this );
}

@Override
Expand Down
Expand Up @@ -28,6 +28,7 @@
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -713,7 +714,70 @@ public long get( TemporalUnit unit )
break;
}
}
throw new UnsupportedOperationException( "Unsupported unit: " + unit );
throw new UnsupportedTemporalTypeException( "Unsupported unit: " + unit );
}

/**
* In contrast to {@link #get(TemporalUnit)}, this method supports more units, namely:
*
* years, hours, minutes, milliseconds, microseconds,
* monthsOfYear, minutesOfHour, secondsOfMinute, millisecondsOfSecond, microsecondsOfSecond, nanosecondsOfSecond
*/
public LongValue get( String fieldName )
{
long val;
switch ( fieldName.toLowerCase() )
{
case "years":
val = months / 12;
break;
case "months":
val = months;
break;
case "monthsofyear":
val = months % 12;
break;
case "days":
val = days;
break;
case "hours":
val = seconds / 3600;
break;
case "minutesofhour":
val = (seconds / 60) % 60;
break;
case "minutes":
val = seconds / 60;
break;
case "secondsofminute":
val = seconds % 60;
break;
case "seconds":
val = seconds;
break;
case "millisecondsofsecond":
val = nanos / 1000_000;
break;
case "milliseconds":
val = seconds * 1000 + nanos / 1000_000;
break;
case "microsecondsofsecond":
val = nanos / 1000;
break;
case "microseconds":
val = seconds * 1000_000 + nanos / 1000;
break;
case "nanosecondsofsecond":
val = nanos;
break;
case "nanoseconds":
val = seconds * NANOS_PER_SECOND + nanos;
break;
default:
throw new UnsupportedTemporalTypeException( "No such field: " + fieldName );
}

return Values.longValue( val );
}

@Override
Expand Down
Expand Up @@ -32,6 +32,7 @@
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -303,6 +304,18 @@ ZoneId getZoneId( Supplier<ZoneId> defaultZone )
return defaultZone.get();
}

@Override
ZoneId getZoneId()
{
throw new UnsupportedTemporalTypeException( "Cannot get the timezone of" + this );
}

@Override
ZoneOffset getZoneOffset()
{
throw new UnsupportedTemporalTypeException( "Cannot get the offset of" + this );
}

@Override
public boolean hasTimeZone()
{
Expand Down
Expand Up @@ -30,6 +30,7 @@
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -219,6 +220,18 @@ ZoneId getZoneId( Supplier<ZoneId> defaultZone )
return defaultZone.get();
}

@Override
ZoneId getZoneId()
{
throw new UnsupportedTemporalTypeException( "Cannot get the timezone of" + this );
}

@Override
ZoneOffset getZoneOffset()
{
throw new UnsupportedTemporalTypeException( "Cannot get the offset of" + this );
}

@Override
public boolean hasTimeZone()
{
Expand Down
Expand Up @@ -23,6 +23,8 @@
import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.chrono.ChronoZonedDateTime;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
Expand All @@ -33,6 +35,7 @@
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.EnumMap;
import java.util.HashMap;
Expand Down Expand Up @@ -69,14 +72,39 @@ public abstract class TemporalValue<T extends Temporal, V extends TemporalValue<

abstract T temporal();

/**
* @return the date part of this temporal, if date is supported.
*/
abstract LocalDate getDatePart();

/**
* @return the local time part of this temporal, if time is supported.
*/
abstract LocalTime getLocalTimePart();

/**
* @return the time part of this temporal, if time is supported.
*/
abstract OffsetTime getTimePart( Supplier<ZoneId> defaultZone );

/**
* @return the zone id, if time is supported. If time is supported, but no timezone, the defaultZone will be used.
* @throws IllegalArgumentException if time is not supported
*/
abstract ZoneId getZoneId( Supplier<ZoneId> defaultZone );

/**
* @return the zone id, if this temporal has a timezone.
* @throws UnsupportedTemporalTypeException if this does not have a timezone
*/
abstract ZoneId getZoneId();

/**
* @return the zone offset, if this temporal has a zone offset.
* @throws UnsupportedTemporalTypeException if this does not have a offset
*/
abstract ZoneOffset getZoneOffset();

abstract boolean hasTimeZone();

abstract boolean hasTime();
Expand Down Expand Up @@ -155,6 +183,37 @@ public final int get( TemporalField field )
return temporal().get( field );
}

public final AnyValue get( String fieldName )
{
Field field = Field.fields.get( fieldName.toLowerCase() );
if ( field == Field.epoch )
{
T temp = temporal();
if ( temp instanceof ChronoZonedDateTime )
{
ChronoZonedDateTime zdt = (ChronoZonedDateTime) temp;
return Values.longValue( zdt.toInstant().toEpochMilli() );
}
else
{
throw new UnsupportedTemporalTypeException( "Epoch not supported." );
}
}
if ( field == Field.timezone )
{
return Values.stringValue( getZoneId(this::getZoneOffset).toString() );
}
if ( field == Field.offset )
{
return Values.stringValue( getZoneOffset().toString() );
}
if ( field == null || field.field == null )
{
throw new UnsupportedTemporalTypeException( "No such field: " + fieldName );
}
return Values.intValue( get( field.field ) );
}

@Override
public <R> R query( TemporalQuery<R> query )
{
Expand Down Expand Up @@ -402,6 +461,26 @@ protected enum Field
millisecond( ChronoField.MILLI_OF_SECOND, 0 ),
microsecond( ChronoField.MICRO_OF_SECOND, 0 ),
nanosecond( ChronoField.NANO_OF_SECOND, 0 ),
// Read only accessors (not assignable)
weekYear( IsoFields.WEEK_BASED_YEAR, 0 )//<pre>
{ //</pre>

@Override
void assign( Builder<?> builder, AnyValue value )
{
throw new IllegalArgumentException( "Not supported: " + name() );
}
},
offset//<pre>
{ //</pre>

@Override
void assign( Builder<?> builder, AnyValue value )
{
throw new IllegalArgumentException( "Not supported: " + name() );
}
},
// time zone
timezone//<pre>
{ //</pre>

Expand Down
Expand Up @@ -29,8 +29,8 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
Expand Down Expand Up @@ -276,6 +276,18 @@ ZoneId getZoneId( Supplier<ZoneId> defaultZone )
return value.getOffset();
}

@Override
ZoneId getZoneId()
{
throw new UnsupportedTemporalTypeException( "Cannot get the timezone of" + this );
}

@Override
ZoneOffset getZoneOffset()
{
return value.getOffset();
}

@Override
public boolean hasTimeZone()
{
Expand Down
Expand Up @@ -94,6 +94,7 @@ Feature "TemporalToStringAcceptance": Scenario "Should serialize date time"
Feature "TemporalToStringAcceptance": Scenario "Should serialize duration"
Feature "TemporalToStringAcceptance": Scenario "Should serialize timezones correctly"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date in last weekYear"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local date time"
Expand Down
Expand Up @@ -32,6 +32,7 @@ Feature "TemporalToStringAcceptance": Scenario "Should serialize date time"
Feature "TemporalToStringAcceptance": Scenario "Should serialize duration"
Feature "TemporalToStringAcceptance": Scenario "Should serialize timezones correctly"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date in last weekYear"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local date time"
Expand Down
Expand Up @@ -8,12 +8,6 @@ Feature "ProcedureCallAcceptance": Scenario "In-query call to unknown procedure
Feature "UnwindAcceptance": Scenario "Pattern comprehension in unwind with empty db"
Feature "UnwindAcceptance": Scenario "Pattern comprehension in unwind with hits"

Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local date time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for duration"
Feature "DurationBetweenAcceptance": Scenario "Should compute duration between two temporals"
Feature "DurationBetweenAcceptance": Scenario "Should compute duration between two temporals in years"
Feature "DurationBetweenAcceptance": Scenario "Should compute duration between two temporals in quarters"
Expand Down
Expand Up @@ -232,6 +232,7 @@ Feature "TemporalToStringAcceptance": Scenario "Should serialize date time"
Feature "TemporalToStringAcceptance": Scenario "Should serialize duration"
Feature "TemporalToStringAcceptance": Scenario "Should serialize timezones correctly"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for date in last weekYear"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for time"
Feature "TemporalAccessorAcceptance": Scenario "Should provide accessors for local date time"
Expand Down

0 comments on commit c109b71

Please sign in to comment.