Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions driver/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -935,4 +935,16 @@
<differenceType>8001</differenceType>
</difference>

<difference>
<className>org/neo4j/driver/types/TypeSystem</className>
<differenceType>7012</differenceType>
<method>org.neo4j.driver.types.Type UNSUPPORTED()</method>
</difference>

<difference>
<className>org/neo4j/driver/Value</className>
<differenceType>7012</differenceType>
<method>org.neo4j.driver.types.UnsupportedType asUnsupportedType()</method>
</difference>

</differences>
14 changes: 14 additions & 0 deletions driver/src/main/java/org/neo4j/driver/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.neo4j.driver.types.Relationship;
import org.neo4j.driver.types.Type;
import org.neo4j.driver.types.TypeSystem;
import org.neo4j.driver.types.UnsupportedType;
import org.neo4j.driver.types.Vector;
import org.neo4j.driver.util.Immutable;
import org.neo4j.driver.util.Preview;
Expand Down Expand Up @@ -495,6 +496,15 @@ public interface Value extends MapAccessor, MapAccessorWithDefaultValue {
*/
Point asPoint();

/**
* Returns the value as an {@link UnsupportedType}, if possible.
*
* @return the value as a {@link UnsupportedType}, if possible
* @throws Uncoercible if value types are incompatible
* @since 6.0.0
*/
UnsupportedType asUnsupportedType();

/**
* Returns the value as a {@link LocalDate}, if possible.
*
Expand Down Expand Up @@ -684,6 +694,10 @@ public interface Value extends MapAccessor, MapAccessorWithDefaultValue {
* <td>{@link TypeSystem#VECTOR}</td>
* <td>{@link Vector}</td>
* </tr>
* <tr>
* <td>{@link TypeSystem#UNSUPPORTED}</td>
* <td>{@link UnsupportedType}</td>
* </tr>
* </tbody>
* </table>
*
Expand Down
12 changes: 12 additions & 0 deletions driver/src/main/java/org/neo4j/driver/Values.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.neo4j.driver.internal.value.PointValue;
import org.neo4j.driver.internal.value.StringValue;
import org.neo4j.driver.internal.value.TimeValue;
import org.neo4j.driver.internal.value.UnsupportedTypeValue;
import org.neo4j.driver.internal.value.VectorValue;
import org.neo4j.driver.mapping.Property;
import org.neo4j.driver.types.Entity;
Expand All @@ -77,6 +78,7 @@
import org.neo4j.driver.types.Point;
import org.neo4j.driver.types.Relationship;
import org.neo4j.driver.types.TypeSystem;
import org.neo4j.driver.types.UnsupportedType;
import org.neo4j.driver.types.Vector;
import org.neo4j.driver.util.Preview;

Expand Down Expand Up @@ -182,6 +184,9 @@ public static Value value(Object value) {
if (value instanceof Vector vector) {
return value(vector);
}
if (value instanceof UnsupportedType) {
return value((UnsupportedType) value);
}

if (value instanceof List<?>) {
return value((List<Object>) value);
Expand Down Expand Up @@ -496,6 +501,9 @@ public static Value value(Stream<Object> stream) {
*/
@Preview(name = "Object mapping")
public static Value value(java.lang.Record record) {
if (record instanceof UnsupportedType unsupportedType) {
return value(unsupportedType);
}
var recordComponents = record.getClass().getRecordComponents();
Map<String, Value> val = new HashMap<>(recordComponents.length);
for (var recordComponent : recordComponents) {
Expand Down Expand Up @@ -1149,4 +1157,8 @@ private static Value vector(Object array) {
"Unsupported vector element type: " + array.getClass().getName());
}
}

private static Value value(UnsupportedType unsupportedType) {
return new UnsupportedTypeValue(unsupportedType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* Licensed 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.neo4j.driver.internal;

import java.util.Optional;
import org.neo4j.driver.types.UnsupportedType;

public record InternalUnsupportedType(String name, String minProtocolVersion, String messageValue)
implements UnsupportedType {
@Override
public Optional<String> message() {
return Optional.ofNullable(messageValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import static org.neo4j.driver.internal.types.TypeConstructor.RELATIONSHIP;
import static org.neo4j.driver.internal.types.TypeConstructor.STRING;
import static org.neo4j.driver.internal.types.TypeConstructor.TIME;
import static org.neo4j.driver.internal.types.TypeConstructor.UNSUPPORTED;
import static org.neo4j.driver.internal.types.TypeConstructor.VECTOR;

import org.neo4j.driver.Value;
Expand Down Expand Up @@ -72,6 +73,7 @@ public class InternalTypeSystem implements TypeSystem {
private final TypeRepresentation durationType = constructType(DURATION);
private final TypeRepresentation nullType = constructType(NULL);
private final TypeRepresentation vectorType = constructType(VECTOR);
private final TypeRepresentation unsupportedType = constructType(UNSUPPORTED);

private InternalTypeSystem() {}

Expand Down Expand Up @@ -180,6 +182,11 @@ public Type VECTOR() {
return vectorType;
}

@Override
public Type UNSUPPORTED() {
return unsupportedType;
}

private TypeRepresentation constructType(TypeConstructor tyCon) {
return new TypeRepresentation(tyCon);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public boolean covers(Value value) {
DATE_TIME,
DURATION,
NULL,
VECTOR;
VECTOR,
UNSUPPORTED;

private static TypeConstructor typeConstructorOf(Value value) {
return ((InternalValue) value).typeConstructor();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.neo4j.bolt.connection.BoltProtocolVersion;
import org.neo4j.bolt.connection.values.Node;
import org.neo4j.bolt.connection.values.Path;
import org.neo4j.bolt.connection.values.Relationship;
import org.neo4j.bolt.connection.values.Segment;
import org.neo4j.bolt.connection.values.Type;
import org.neo4j.bolt.connection.values.Value;
import org.neo4j.bolt.connection.values.ValueFactory;
import org.neo4j.driver.Values;
import org.neo4j.driver.internal.InternalNode;
import org.neo4j.driver.internal.InternalPath;
import org.neo4j.driver.internal.InternalRelationship;
import org.neo4j.driver.internal.InternalUnsupportedType;

public class BoltValueFactory implements ValueFactory {
private static final BoltValueFactory INSTANCE = new BoltValueFactory();
Expand Down Expand Up @@ -265,6 +268,15 @@ public Value vector(Class<?> elementType, Object elements) {
return value;
}

@Override
public Value unsupportedType(String name, BoltProtocolVersion minBoltVersion, Map<String, Value> extra) {
var message = extra.get("message");
var messageString =
message != null ? message.boltValueType().equals(Type.STRING) ? message.asString() : null : null;
return (InternalValue)
Values.value((Object) new InternalUnsupportedType(name, minBoltVersion.toString(), messageString));
}

@Override
public Value unsupportedDateTimeValue(DateTimeException e) {
return new UnsupportedDateTimeValue(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* Licensed 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.neo4j.driver.internal.value;

import org.neo4j.driver.internal.types.InternalTypeSystem;
import org.neo4j.driver.types.UnsupportedType;

public final class UnsupportedTypeValue extends ObjectValueAdapter<UnsupportedType> {
public UnsupportedTypeValue(UnsupportedType adapted) {
super(adapted);
}

@Override
public org.neo4j.bolt.connection.values.Type boltValueType() {
return org.neo4j.bolt.connection.values.Type.UNSUPPORTED;
}

@Override
public org.neo4j.driver.types.Type type() {
return InternalTypeSystem.TYPE_SYSTEM.UNSUPPORTED();
}

@Override
public UnsupportedType asUnsupportedType() {
return asObject();
}

@Override
public <T> T as(Class<T> targetClass) {
if (targetClass.isAssignableFrom(UnsupportedType.class)) {
return targetClass.cast(asObject());
}
return asMapped(targetClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.neo4j.driver.types.Point;
import org.neo4j.driver.types.Relationship;
import org.neo4j.driver.types.Type;
import org.neo4j.driver.types.UnsupportedType;

public abstract class ValueAdapter extends InternalMapAccessorWithDefaultValue implements InternalValue {
@Override
Expand Down Expand Up @@ -305,6 +306,11 @@ public Point asPoint() {
throw new Uncoercible(type().name(), "Point");
}

@Override
public UnsupportedType asUnsupportedType() {
throw new Uncoercible(type().name(), "UnsupportedType");
}

@Override
public Value get(int index) {
throw new NotMultiValued(type().name() + " is not an indexed collection");
Expand Down
16 changes: 16 additions & 0 deletions driver/src/main/java/org/neo4j/driver/types/TypeSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,20 @@ static TypeSystem getDefault() {
*/
@Preview(name = "Neo4j Vector")
Type VECTOR();

/**
* Returns a {@link Type} instance representing an unsupported type.
* <p>
* An unsupported type may occur when a new type is introduced in the Neo4j server and the driver is connected over
* an older Bolt Protocol version that does not support this type. The {@link UnsupportedType} object provides
* information about the unsupported type and the {@link UnsupportedType#minProtocolVersion()} needed to support
* it. However, the {@link UnsupportedType} object itself requires at least Bolt Protocol 6.0.
* <p>
* Note that the unsupported type MUST NOT be sent to the server.
*
* @return the type instance
* @since 6.0.0
* @see UnsupportedType
*/
Type UNSUPPORTED();
}
48 changes: 48 additions & 0 deletions driver/src/main/java/org/neo4j/driver/types/UnsupportedType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* Licensed 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.neo4j.driver.types;

import java.util.Optional;

/**
* An object instance of {@link TypeSystem#UNSUPPORTED()} type.
* <p>
* This object holds information about the unsupported type and the {@link #minProtocolVersion()} needed to support it.
* <p>
* Note that this object MUST NOT be sent to the server.
*
* @since 6.0.0
*/
public interface UnsupportedType {
/**
* Returns the type name.
* @return the type name
*/
String name();

/**
* The minimum Bolt Protocol version needed to support this type.
* @return the minimum Bolt Protocol version
*/
String minProtocolVersion();

/**
* An optional message.
* @return the message
*/
Optional<String> message();
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@
import org.neo4j.driver.internal.InternalPoint3D;
import org.neo4j.driver.internal.InternalRecord;
import org.neo4j.driver.internal.InternalRelationship;
import org.neo4j.driver.internal.InternalUnsupportedType;
import org.neo4j.driver.internal.value.NodeValue;
import org.neo4j.driver.internal.value.RelationshipValue;
import org.neo4j.driver.mapping.Property;
import org.neo4j.driver.types.Float64Vector;
import org.neo4j.driver.types.IsoDuration;
import org.neo4j.driver.types.Point;
import org.neo4j.driver.types.UnsupportedType;

final class ObjectMappingIT {
@ParameterizedTest
Expand All @@ -77,6 +79,7 @@ void shouldMapValue(Function<Map<String, Value>, ValueHolder> valueFunction) {
var point2d = (Point) new InternalPoint2D(0, 0, 0);
var point3d = (Point) new InternalPoint3D(0, 0, 0, 0);
var vector = new InternalFloat64Vector(new double[] {0.0, 100.0});
var unsupportedType = new InternalUnsupportedType("name", "99.99", "message");

var properties = Map.ofEntries(
Map.entry("string", Values.value(string)),
Expand All @@ -101,7 +104,8 @@ void shouldMapValue(Function<Map<String, Value>, ValueHolder> valueFunction) {
Map.entry("javaDuration", Values.value(javaDuration)),
Map.entry("point2d", Values.value(point2d)),
Map.entry("point3d", Values.value(point3d)),
Map.entry("vector", Values.value(vector)));
Map.entry("vector", Values.value(vector)),
Map.entry("unsupportedType", Values.value(unsupportedType)));

// when
var valueHolder = valueFunction.apply(properties);
Expand All @@ -125,6 +129,7 @@ void shouldMapValue(Function<Map<String, Value>, ValueHolder> valueFunction) {
assertEquals(point2d, valueHolder.point2d());
assertEquals(point3d, valueHolder.point3d());
assertEquals(vector, valueHolder.vector());
assertEquals(unsupportedType, valueHolder.unsupportedType());
}

static Stream<Arguments> shouldMapValueArgs() {
Expand Down Expand Up @@ -167,7 +172,8 @@ public record ValueHolder(
Duration javaDuration,
Point point2d,
Point point3d,
Float64Vector vector) {}
Float64Vector vector,
UnsupportedType unsupportedType) {}

public record StringValueHolder(String string) {}

Expand Down
Loading