diff --git a/community/csv/src/main/java/org/neo4j/csv/reader/BufferedCharSeeker.java b/community/csv/src/main/java/org/neo4j/csv/reader/BufferedCharSeeker.java index 88a3b536077bc..5414d86d50170 100644 --- a/community/csv/src/main/java/org/neo4j/csv/reader/BufferedCharSeeker.java +++ b/community/csv/src/main/java/org/neo4j/csv/reader/BufferedCharSeeker.java @@ -24,6 +24,7 @@ import java.io.Reader; import org.neo4j.csv.reader.Source.Chunk; +import org.neo4j.values.AnyValue; import static java.lang.String.format; @@ -273,7 +274,7 @@ private static boolean getTrimStringIgnoreErrors( Configuration config ) } @Override - public > EXTRACTOR extract( Mark mark, EXTRACTOR extractor, String optionalData ) + public > EXTRACTOR extract( Mark mark, EXTRACTOR extractor, AnyValue[] optionalData ) { if ( !tryExtract( mark, extractor, optionalData ) ) { @@ -284,7 +285,7 @@ public > EXTRACTOR extract( Mark mark, EXTRACTOR } @Override - public boolean tryExtract( Mark mark, Extractor extractor, String optionalData ) + public boolean tryExtract( Mark mark, Extractor extractor, AnyValue[] optionalData ) { int from = mark.startPosition(); int to = mark.position(); diff --git a/community/csv/src/main/java/org/neo4j/csv/reader/CharSeeker.java b/community/csv/src/main/java/org/neo4j/csv/reader/CharSeeker.java index f77f61d0dbf3e..dc399eba4e784 100644 --- a/community/csv/src/main/java/org/neo4j/csv/reader/CharSeeker.java +++ b/community/csv/src/main/java/org/neo4j/csv/reader/CharSeeker.java @@ -22,10 +22,11 @@ import java.io.Closeable; import java.io.IOException; +import org.neo4j.values.AnyValue; /** * Seeks for specific characters in a stream of characters, e.g. a {@link CharReadable}. Uses a {@link Mark} * as keeper of position. Once a {@link #seek(Mark, int)} has succeeded the characters specified by - * the mark can be {@link #extract(Mark, Extractor, String) extracted} into a value of an arbitrary type. + * the mark can be {@link #extract(Mark, Extractor, AnyValue[]) extracted} into a value of an arbitrary type. * * Typical usage is: * @@ -69,10 +70,10 @@ public interface CharSeeker extends Closeable, SourceTraceability * @param optionalData holds additional information for spatial and temporal values or null * @return the supplied {@link Extractor}, which after the call carries the extracted value itself, * where either {@link Extractor#value()} or a more specific accessor method can be called to access the value. - * @throws IllegalStateException if the {@link Extractor#extract(char[], int, int, boolean, String) extraction} + * @throws IllegalStateException if the {@link Extractor#extract(char[], int, int, boolean, AnyValue[]) extraction} * returns {@code false}. */ - > EXTRACTOR extract( Mark mark, EXTRACTOR extractor, String optionalData ); + > EXTRACTOR extract( Mark mark, EXTRACTOR extractor, AnyValue[] optionalData ); /** * Extracts the value specified by the {@link Mark}, previously populated by a call to {@link #seek(Mark, int)}. @@ -80,7 +81,7 @@ public interface CharSeeker extends Closeable, SourceTraceability * @param extractor {@link Extractor} capable of extracting the value. * @return the supplied {@link Extractor}, which after the call carries the extracted value itself, * where either {@link Extractor#value()} or a more specific accessor method can be called to access the value. - * @throws IllegalStateException if the {@link Extractor#extract(char[], int, int, boolean, String) extraction} + * @throws IllegalStateException if the {@link Extractor#extract(char[], int, int, boolean, AnyValue[]) extraction} * returns {@code false}. */ > EXTRACTOR extract( Mark mark, EXTRACTOR extractor ); @@ -93,7 +94,7 @@ public interface CharSeeker extends Closeable, SourceTraceability * @return {@code true} if a value was extracted, otherwise {@code false}. Probably the only reason for * returning {@code false} would be if the data to extract was empty. */ - boolean tryExtract( Mark mark, Extractor extractor, String optionalData ); + boolean tryExtract( Mark mark, Extractor extractor, AnyValue[] optionalData ); /** * Extracts the value specified by the {@link Mark}, previously populated by a call to {@link #seek(Mark, int)}. diff --git a/community/csv/src/main/java/org/neo4j/csv/reader/Extractor.java b/community/csv/src/main/java/org/neo4j/csv/reader/Extractor.java index 53ebb09ea2634..916bb99f8ef3a 100644 --- a/community/csv/src/main/java/org/neo4j/csv/reader/Extractor.java +++ b/community/csv/src/main/java/org/neo4j/csv/reader/Extractor.java @@ -19,6 +19,7 @@ */ package org.neo4j.csv.reader; +import org.neo4j.values.AnyValue; /** * Extracts a value from a part of a {@code char[]} into any type of value, f.ex. a {@link Extractors#string()}, * {@link Extractors#long_() long} or {@link Extractors#intArray()}. @@ -40,10 +41,10 @@ public interface Extractor extends Cloneable * @param offset offset into the buffer where the value starts. * @param length number of characters from the offset to extract. * @param hadQuotes whether or not there were skipped characters, f.ex. quotation. - * @param optionalData optional data to be used for spatial (CRS) or temporal (timezone) values or null + * @param optionalData optional data to be used for spatial or temporal values or null if csv header did not use it * @return {@code true} if a value was extracted, otherwise {@code false}. */ - boolean extract( char[] data, int offset, int length, boolean hadQuotes, String optionalData ); + boolean extract( char[] data, int offset, int length, boolean hadQuotes, AnyValue[] optionalData ); /** * Extracts value of type {@code T} from the given character data. diff --git a/community/csv/src/main/java/org/neo4j/csv/reader/Extractors.java b/community/csv/src/main/java/org/neo4j/csv/reader/Extractors.java index 8de312d326d50..d947f82e50ebd 100644 --- a/community/csv/src/main/java/org/neo4j/csv/reader/Extractors.java +++ b/community/csv/src/main/java/org/neo4j/csv/reader/Extractors.java @@ -349,7 +349,7 @@ private abstract static class AbstractSingleValueExtractor extends AbstractEx } @Override - public final boolean extract( char[] data, int offset, int length, boolean hadQuotes, String optionalData ) + public final boolean extract( char[] data, int offset, int length, boolean hadQuotes, AnyValue[] optionalData ) { if ( nullValue( length, hadQuotes ) ) { @@ -372,7 +372,7 @@ protected boolean nullValue( int length, boolean hadQuotes ) protected abstract void clear(); - protected abstract boolean extract0( char[] data, int offset, int length, String optionalData ); + protected abstract boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ); } private abstract static class AbstractSingleAnyValueExtractor extends AbstractSingleValueExtractor @@ -421,7 +421,7 @@ protected boolean nullValue( int length, boolean hadQuotes ) } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = new String( data, offset, length ); return true; @@ -450,7 +450,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = extractLong( data, offset, length ); return true; @@ -488,7 +488,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = safeCastLongToInt( extractLong( data, offset, length ) ); return true; @@ -526,7 +526,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = safeCastLongToShort( extractLong( data, offset, length ) ); return true; @@ -564,7 +564,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = safeCastLongToByte( extractLong( data, offset, length ) ); return true; @@ -609,7 +609,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = extractBoolean( data, offset, length ); return true; @@ -643,7 +643,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { if ( length > 1 ) { @@ -681,7 +681,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { try { @@ -724,7 +724,7 @@ protected void clear() } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { try { @@ -769,7 +769,7 @@ public T value() } @Override - public boolean extract( char[] data, int offset, int length, boolean hadQuotes, String optionalData ) + public boolean extract( char[] data, int offset, int length, boolean hadQuotes, AnyValue[] optionalData ) { extract0( data, offset, length, optionalData ); return true; @@ -781,7 +781,7 @@ public boolean extract( char[] data, int offset, int length, boolean hadQuotes ) return extract( data, offset, length, hadQuotes, null ); } - protected abstract void extract0( char[] data, int offset, int length, String optionalData ); + protected abstract void extract0( char[] data, int offset, int length, AnyValue[] optionalData ); protected int charsToNextDelimiter( char[] data, int offset, int length ) { @@ -833,7 +833,7 @@ private static class StringArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalData ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new String[numberOfValues] : EMPTY; @@ -860,7 +860,7 @@ private static class ByteArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalData ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new byte[numberOfValues] : EMPTY; @@ -883,7 +883,7 @@ private static class ShortArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalData ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new short[numberOfValues] : EMPTY; @@ -906,7 +906,7 @@ private static class IntArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalDatah ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalDatah ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new int[numberOfValues] : EMPTY; @@ -927,7 +927,7 @@ private static class LongArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalData ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new long[numberOfValues] : EMPTY_LONG_ARRAY; @@ -950,7 +950,7 @@ private static class FloatArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalData ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new float[numberOfValues] : EMPTY; @@ -975,7 +975,7 @@ private static class DoubleArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalData ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new double[numberOfValues] : EMPTY; @@ -1000,7 +1000,7 @@ private static class BooleanArrayExtractor extends ArrayExtractor } @Override - protected void extract0( char[] data, int offset, int length, String optionalData ) + protected void extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { int numberOfValues = numberOfValues( data, offset, length ); value = numberOfValues > 0 ? new boolean[numberOfValues] : EMPTY; @@ -1021,7 +1021,7 @@ public static class PointExtractor extends AbstractSingleAnyValueExtractor } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = PointValue.parse( CharBuffer.wrap( data, offset, length ), optionalData ); return true; @@ -1042,7 +1042,7 @@ public static class DateExtractor extends AbstractSingleAnyValueExtractor } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { //TODO: Change DateValue parse to use optionalData value = DateValue.parse( CharBuffer.wrap( data, offset, length ) ); @@ -1067,7 +1067,7 @@ public static class TimeExtractor extends AbstractSingleAnyValueExtractor } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = TimeValue.parse( CharBuffer.wrap( data, offset, length ), defaultTimeZone ); return true; @@ -1091,7 +1091,7 @@ public static class DateTimeExtractor extends AbstractSingleAnyValueExtractor } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = DateTimeValue.parse( CharBuffer.wrap( data, offset, length ), defaultTimeZone ); return true; @@ -1112,7 +1112,7 @@ public static class LocalTimeExtractor extends AbstractSingleAnyValueExtractor } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = LocalTimeValue.parse( CharBuffer.wrap( data, offset, length ) ); return true; @@ -1133,7 +1133,7 @@ public static class LocalDateTimeExtractor extends AbstractSingleAnyValueExtract } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = LocalDateTimeValue.parse( CharBuffer.wrap( data, offset, length ) ); return true; @@ -1154,7 +1154,7 @@ public static class DurationExtractor extends AbstractSingleAnyValueExtractor } @Override - protected boolean extract0( char[] data, int offset, int length, String optionalData ) + protected boolean extract0( char[] data, int offset, int length, AnyValue[] optionalData ) { value = DurationValue.parse( CharBuffer.wrap( data, offset, length ) ); return true; diff --git a/community/csv/src/test/java/org/neo4j/csv/reader/ExtractorsTest.java b/community/csv/src/test/java/org/neo4j/csv/reader/ExtractorsTest.java index 7c2de4c5b42a4..3e96b8bab1901 100644 --- a/community/csv/src/test/java/org/neo4j/csv/reader/ExtractorsTest.java +++ b/community/csv/src/test/java/org/neo4j/csv/reader/ExtractorsTest.java @@ -145,7 +145,8 @@ public void shouldExtractPoint() // WHEN char[] asChars = "Point{latitude: 56.7, longitude: 13.2}".toCharArray(); Extractors.PointExtractor extractor = extractors.point(); - extractor.extract( asChars, 0, asChars.length, false, "WGS-84" ); + String headerInfo = "{crs:WGS-84}"; + extractor.extract( asChars, 0, asChars.length, false, PointValue.parseIntoArray( headerInfo ) ); // THEN assertEquals( value, extractor.value ); diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/DataFactories.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/DataFactories.java index 1af547dba5f3b..8ac556afc9b9d 100644 --- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/DataFactories.java +++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/DataFactories.java @@ -45,6 +45,8 @@ import org.neo4j.unsafe.impl.batchimport.input.HeaderException; import org.neo4j.unsafe.impl.batchimport.input.MissingHeaderException; import org.neo4j.unsafe.impl.batchimport.input.csv.Header.Entry; +import org.neo4j.values.AnyValue; +import org.neo4j.values.storable.PointValue; import static java.lang.String.format; import static java.time.ZoneOffset.UTC; @@ -295,7 +297,10 @@ private static class HeaderEntrySpec String groupName = null; int typeIndex; - if ( rawHeaderField != null && (typeIndex = rawHeaderField.lastIndexOf( ':' )) != -1 ) + + String rawHeaderUntilOptions = rawHeaderField.split( "\\{" )[0]; + + if ( rawHeaderField != null && (typeIndex = rawHeaderUntilOptions.lastIndexOf( ':' )) != -1 ) { // Specific type given name = typeIndex > 0 ? rawHeaderField.substring( 0, typeIndex ) : null; type = rawHeaderField.substring( typeIndex + 1 ); @@ -334,7 +339,7 @@ protected Header.Entry entry( int index, String name, String typeSpec, Group gro // like 'int' or 'string_array' or similar, or empty for 'string' property. Type type = null; Extractor extractor = null; - String optionalParameter = null; + AnyValue[] optionalParameter = null; if ( typeSpec == null ) { type = Type.PROPERTY; @@ -344,8 +349,11 @@ protected Header.Entry entry( int index, String name, String typeSpec, Group gro { Pair split = splitTypeSpecAndOptionalParameter(typeSpec); typeSpec = split.first(); - optionalParameter = split.other(); - + String optionalParameterString = split.other(); + if ( optionalParameterString != null ) + { + optionalParameter = PointValue.parseIntoArray( optionalParameterString ); + } if ( typeSpec.equalsIgnoreCase( Type.ID.name() ) ) { type = Type.ID; @@ -384,7 +392,7 @@ protected Header.Entry entry( int index, String name, String typeSpec, Group gro { Type type = null; Extractor extractor = null; - String optionalParameter = null; + AnyValue[] optionalParameter = null; if ( typeSpec == null ) { // Property type = Type.PROPERTY; @@ -392,9 +400,13 @@ protected Header.Entry entry( int index, String name, String typeSpec, Group gro } else { - Pair split = splitTypeSpecAndOptionalParameter(typeSpec); + Pair split = splitTypeSpecAndOptionalParameter( typeSpec ); typeSpec = split.first(); - optionalParameter = split.other(); + String optionalParameterString = split.other(); + if ( optionalParameterString != null ) + { + optionalParameter = PointValue.parseIntoArray( optionalParameterString ); + } if ( typeSpec.equalsIgnoreCase( Type.START_ID.name() ) ) { @@ -459,7 +471,7 @@ public static Pair splitTypeSpecAndOptionalParameter( String type String errorMessage = format( "Failed to parse header: '%s'", typeSpec ); throw new IllegalArgumentException( errorMessage ); } - optionalParameter = typeSpec.substring( begin + 1, end ).trim(); + optionalParameter = typeSpec.substring( begin, end +1 ); newTypeSpec = typeSpec.substring( 0, begin ); } return Pair.of( newTypeSpec, optionalParameter ); diff --git a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/Header.java b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/Header.java index e0b9dd7a5ca06..d4244df03fa3b 100644 --- a/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/Header.java +++ b/community/kernel/src/main/java/org/neo4j/unsafe/impl/batchimport/input/csv/Header.java @@ -26,6 +26,7 @@ import org.neo4j.csv.reader.Extractor; import org.neo4j.unsafe.impl.batchimport.input.Group; import org.neo4j.unsafe.impl.batchimport.input.Groups; +import org.neo4j.values.AnyValue; /** * Header of tabular/csv data input, specifying meta data about values in each "column", for example @@ -104,7 +105,7 @@ public static class Entry implements Cloneable private final Type type; private final Group group; private final Extractor extractor; - private final String optionalParameter; // This can be used to encapsulate the parameter set in the header for spatial and temporal columns + private final AnyValue[] optionalParameter; // This can be used to encapsulate the parameters set in the header for spatial and temporal columns public Entry( String name, Type type, Group group, Extractor extractor ) { @@ -115,7 +116,7 @@ public Entry( String name, Type type, Group group, Extractor extractor ) this.optionalParameter = null; } - public Entry( String name, Type type, Group group, Extractor extractor, String optionalParameter ) + public Entry( String name, Type type, Group group, Extractor extractor, AnyValue[] optionalParameter ) { this.name = name; this.type = type; @@ -160,7 +161,7 @@ public String name() return name; } - public String optionalParameter() + public AnyValue[] optionalParameter() { return optionalParameter; } diff --git a/community/kernel/src/test/java/org/neo4j/unsafe/impl/batchimport/input/csv/CsvInputBatchImportIT.java b/community/kernel/src/test/java/org/neo4j/unsafe/impl/batchimport/input/csv/CsvInputBatchImportIT.java index 0e69d32ab916b..6875fb8ff6283 100644 --- a/community/kernel/src/test/java/org/neo4j/unsafe/impl/batchimport/input/csv/CsvInputBatchImportIT.java +++ b/community/kernel/src/test/java/org/neo4j/unsafe/impl/batchimport/input/csv/CsvInputBatchImportIT.java @@ -265,7 +265,7 @@ private File nodeDataAsFile( List nodeData ) throws IOException try ( Writer writer = fileSystemRule.get().openAsWriter( file, StandardCharsets.UTF_8, false ) ) { // Header - println( writer, "id:ID,name,pointA:Point{WGS-84},pointB:Point,date:Date,time:Time,dateTime:DateTime,dateTime2:DateTime,localTime:LocalTime," + + println( writer, "id:ID,name,pointA:Point{crs:WGS-84},pointB:Point,date:Date,time:Time,dateTime:DateTime,dateTime2:DateTime,localTime:LocalTime," + "localDateTime:LocalDateTime,duration:Duration,some-labels:LABEL" ); // Data diff --git a/community/values/src/main/java/org/neo4j/values/storable/PointValue.java b/community/values/src/main/java/org/neo4j/values/storable/PointValue.java index 7401cdd5e1eca..641b020968987 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/PointValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/PointValue.java @@ -284,7 +284,25 @@ public static PointValue parse( CharSequence text ) return PointValue.parse( text, null ); } - public static PointValue parse( CharSequence text, String crs ) + public static PointValue parse( CharSequence text, AnyValue[] fieldsFromHeader ) + { + AnyValue[] fieldsFromData = parseIntoArray( text ); + if ( fieldsFromHeader != null ) + { + //It is given that fieldsFromData.length == fieldsFromHeader.length because parseIntoArray produces fixed length arrays + // Merge InputFields: Data fields override header fields + for ( int i = 0; i < fieldsFromData.length; i++ ) + { + if ( fieldsFromData[i] == null ) + { + fieldsFromData[i] = fieldsFromHeader[i]; + } + } + } + return fromInputFields( fieldsFromData ); + } + + public static AnyValue[] parseIntoArray(CharSequence text) { Matcher mapMatcher = mapPattern.matcher( text ); if ( !(mapMatcher.find() && mapMatcher.groupCount() == 1) ) @@ -351,19 +369,7 @@ public static PointValue parse( CharSequence text, String crs ) { // Eliminate any quoutes String unquotedValue = quotesPattern.matcher( value ).replaceAll( "" ); - if ( crs != null ) // global crs is given - { - if ( !crs.toLowerCase().equals( unquotedValue.toLowerCase() ) ) - { - throw new IllegalArgumentException( - "Conflicting crs attributes for point found. Header crs states '" + crs + "' while column specifies '" + - unquotedValue + "'" ); - } - } - else - { - fields[field.ordinal()] = Values.stringValue( unquotedValue ); - } + fields[field.ordinal()] = Values.stringValue( unquotedValue ); break; } @@ -375,12 +381,7 @@ public static PointValue parse( CharSequence text, String crs ) } } while ( matcher.find() ); - if ( crs != null ) - { - fields[PointValueField.CRS.ordinal()] = Values.stringValue( crs ); - } - - return fromInputFields( fields ); + return fields; } /** diff --git a/community/values/src/test/java/org/neo4j/values/storable/PointTest.java b/community/values/src/test/java/org/neo4j/values/storable/PointTest.java index 96e6a0033ca99..cc1ae36b3faef 100644 --- a/community/values/src/test/java/org/neo4j/values/storable/PointTest.java +++ b/community/values/src/test/java/org/neo4j/values/storable/PointTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.neo4j.values.storable.CoordinateReferenceSystem.Cartesian; import static org.neo4j.values.storable.CoordinateReferenceSystem.Cartesian_3D; import static org.neo4j.values.storable.CoordinateReferenceSystem.WGS84; @@ -112,16 +113,36 @@ public void shouldBeAbleToParsePointWithUnquotedCrs() } @Test - public void shouldNotBeAbleToParsePointWithConflictingCrsInformation() + public void shouldBeAbleToParsePointThatOverridesHeaderInformation() { + String headerInformation = "{crs:wgs-84}"; + String data = "{latitude: 40.7128, longitude: -74.0060, height: 567.8, crs:wgs-84-3D}"; + + PointValue expected = PointValue.parse( data ); + PointValue actual = PointValue.parse( data, PointValue.parseIntoArray( headerInformation ) ); + + assertEqual( expected, actual ); + assertEquals( "wgs-84-3d", actual.getCoordinateReferenceSystem().getName().toLowerCase() ); + } + + @Test + public void shouldBeAbleToParseIncompletePointWithHeaderInformation() + { + String headerInformation = "{latitude: 40.7128}"; + String data = "{longitude: -74.0060, height: 567.8, crs:wgs-84-3D}"; + try { - PointValue.parse( "{latitude: 40.7128, longitude: -74.0060, height: 567.8, crs:wgs-84-3D}", "wgs-84" ); - } - catch ( IllegalArgumentException e ) - { - assertEquals( "Conflicting crs attributes for point found. Header crs states 'wgs-84' while column specifies 'wgs-84-3D'", e.getMessage() ); + PointValue.parse( data ); // this shouldn't work + fail("Was able to parse point although latitude was missing"); + + } catch (IllegalArgumentException e){ + // this is expected } + + // this should work + PointValue.parse( data, PointValue.parseIntoArray( headerInformation ) ); + } @Test