Skip to content

Commit 4dc7edf

Browse files
authored
feat(unsupportedType): add support for Bolt Unsupported Type (#1691)
This update adds support for a new `TypeSystem#UNSUPPORTED()` type. The 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. A new `UnsupportedType` object provides information about the unsupported type and the minimum Bolt version needed to support it. However, the `UnsupportedType` object itself requires at least Bolt Protocol 6.0.
1 parent ee9a0e5 commit 4dc7edf

File tree

16 files changed

+282
-13
lines changed

16 files changed

+282
-13
lines changed

driver/clirr-ignored-differences.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,4 +935,16 @@
935935
<differenceType>8001</differenceType>
936936
</difference>
937937

938+
<difference>
939+
<className>org/neo4j/driver/types/TypeSystem</className>
940+
<differenceType>7012</differenceType>
941+
<method>org.neo4j.driver.types.Type UNSUPPORTED()</method>
942+
</difference>
943+
944+
<difference>
945+
<className>org/neo4j/driver/Value</className>
946+
<differenceType>7012</differenceType>
947+
<method>org.neo4j.driver.types.UnsupportedType asUnsupportedType()</method>
948+
</difference>
949+
938950
</differences>

driver/src/main/java/org/neo4j/driver/Value.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.neo4j.driver.types.Relationship;
4343
import org.neo4j.driver.types.Type;
4444
import org.neo4j.driver.types.TypeSystem;
45+
import org.neo4j.driver.types.UnsupportedType;
4546
import org.neo4j.driver.types.Vector;
4647
import org.neo4j.driver.util.Immutable;
4748
import org.neo4j.driver.util.Preview;
@@ -495,6 +496,15 @@ public interface Value extends MapAccessor, MapAccessorWithDefaultValue {
495496
*/
496497
Point asPoint();
497498

499+
/**
500+
* Returns the value as an {@link UnsupportedType}, if possible.
501+
*
502+
* @return the value as a {@link UnsupportedType}, if possible
503+
* @throws Uncoercible if value types are incompatible
504+
* @since 6.0.0
505+
*/
506+
UnsupportedType asUnsupportedType();
507+
498508
/**
499509
* Returns the value as a {@link LocalDate}, if possible.
500510
*
@@ -684,6 +694,10 @@ public interface Value extends MapAccessor, MapAccessorWithDefaultValue {
684694
* <td>{@link TypeSystem#VECTOR}</td>
685695
* <td>{@link Vector}</td>
686696
* </tr>
697+
* <tr>
698+
* <td>{@link TypeSystem#UNSUPPORTED}</td>
699+
* <td>{@link UnsupportedType}</td>
700+
* </tr>
687701
* </tbody>
688702
* </table>
689703
*

driver/src/main/java/org/neo4j/driver/Values.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import org.neo4j.driver.internal.value.PointValue;
6868
import org.neo4j.driver.internal.value.StringValue;
6969
import org.neo4j.driver.internal.value.TimeValue;
70+
import org.neo4j.driver.internal.value.UnsupportedTypeValue;
7071
import org.neo4j.driver.internal.value.VectorValue;
7172
import org.neo4j.driver.mapping.Property;
7273
import org.neo4j.driver.types.Entity;
@@ -77,6 +78,7 @@
7778
import org.neo4j.driver.types.Point;
7879
import org.neo4j.driver.types.Relationship;
7980
import org.neo4j.driver.types.TypeSystem;
81+
import org.neo4j.driver.types.UnsupportedType;
8082
import org.neo4j.driver.types.Vector;
8183
import org.neo4j.driver.util.Preview;
8284

@@ -182,6 +184,9 @@ public static Value value(Object value) {
182184
if (value instanceof Vector vector) {
183185
return value(vector);
184186
}
187+
if (value instanceof UnsupportedType) {
188+
return value((UnsupportedType) value);
189+
}
185190

186191
if (value instanceof List<?>) {
187192
return value((List<Object>) value);
@@ -496,6 +501,9 @@ public static Value value(Stream<Object> stream) {
496501
*/
497502
@Preview(name = "Object mapping")
498503
public static Value value(java.lang.Record record) {
504+
if (record instanceof UnsupportedType unsupportedType) {
505+
return value(unsupportedType);
506+
}
499507
var recordComponents = record.getClass().getRecordComponents();
500508
Map<String, Value> val = new HashMap<>(recordComponents.length);
501509
for (var recordComponent : recordComponents) {
@@ -1149,4 +1157,8 @@ private static Value vector(Object array) {
11491157
"Unsupported vector element type: " + array.getClass().getName());
11501158
}
11511159
}
1160+
1161+
private static Value value(UnsupportedType unsupportedType) {
1162+
return new UnsupportedTypeValue(unsupportedType);
1163+
}
11521164
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal;
18+
19+
import java.util.Optional;
20+
import org.neo4j.driver.types.UnsupportedType;
21+
22+
public record InternalUnsupportedType(String name, String minProtocolVersion, String messageValue)
23+
implements UnsupportedType {
24+
@Override
25+
public Optional<String> message() {
26+
return Optional.ofNullable(messageValue);
27+
}
28+
}

driver/src/main/java/org/neo4j/driver/internal/types/InternalTypeSystem.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import static org.neo4j.driver.internal.types.TypeConstructor.RELATIONSHIP;
3737
import static org.neo4j.driver.internal.types.TypeConstructor.STRING;
3838
import static org.neo4j.driver.internal.types.TypeConstructor.TIME;
39+
import static org.neo4j.driver.internal.types.TypeConstructor.UNSUPPORTED;
3940
import static org.neo4j.driver.internal.types.TypeConstructor.VECTOR;
4041

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

7678
private InternalTypeSystem() {}
7779

@@ -180,6 +182,11 @@ public Type VECTOR() {
180182
return vectorType;
181183
}
182184

185+
@Override
186+
public Type UNSUPPORTED() {
187+
return unsupportedType;
188+
}
189+
183190
private TypeRepresentation constructType(TypeConstructor tyCon) {
184191
return new TypeRepresentation(tyCon);
185192
}

driver/src/main/java/org/neo4j/driver/internal/types/TypeConstructor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ public boolean covers(Value value) {
5757
DATE_TIME,
5858
DURATION,
5959
NULL,
60-
VECTOR;
60+
VECTOR,
61+
UNSUPPORTED;
6162

6263
private static TypeConstructor typeConstructorOf(Value value) {
6364
return ((InternalValue) value).typeConstructor();

driver/src/main/java/org/neo4j/driver/internal/value/BoltValueFactory.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,19 @@
2929
import java.util.Collections;
3030
import java.util.List;
3131
import java.util.Map;
32+
import org.neo4j.bolt.connection.BoltProtocolVersion;
3233
import org.neo4j.bolt.connection.values.Node;
3334
import org.neo4j.bolt.connection.values.Path;
3435
import org.neo4j.bolt.connection.values.Relationship;
3536
import org.neo4j.bolt.connection.values.Segment;
37+
import org.neo4j.bolt.connection.values.Type;
3638
import org.neo4j.bolt.connection.values.Value;
3739
import org.neo4j.bolt.connection.values.ValueFactory;
3840
import org.neo4j.driver.Values;
3941
import org.neo4j.driver.internal.InternalNode;
4042
import org.neo4j.driver.internal.InternalPath;
4143
import org.neo4j.driver.internal.InternalRelationship;
44+
import org.neo4j.driver.internal.InternalUnsupportedType;
4245

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

271+
@Override
272+
public Value unsupportedType(String name, BoltProtocolVersion minBoltVersion, Map<String, Value> extra) {
273+
var message = extra.get("message");
274+
var messageString =
275+
message != null ? message.boltValueType().equals(Type.STRING) ? message.asString() : null : null;
276+
return (InternalValue)
277+
Values.value((Object) new InternalUnsupportedType(name, minBoltVersion.toString(), messageString));
278+
}
279+
268280
@Override
269281
public Value unsupportedDateTimeValue(DateTimeException e) {
270282
return new UnsupportedDateTimeValue(e);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [https://neo4j.com]
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.neo4j.driver.internal.value;
18+
19+
import org.neo4j.driver.internal.types.InternalTypeSystem;
20+
import org.neo4j.driver.types.UnsupportedType;
21+
22+
public final class UnsupportedTypeValue extends ObjectValueAdapter<UnsupportedType> {
23+
public UnsupportedTypeValue(UnsupportedType adapted) {
24+
super(adapted);
25+
}
26+
27+
@Override
28+
public org.neo4j.bolt.connection.values.Type boltValueType() {
29+
return org.neo4j.bolt.connection.values.Type.UNSUPPORTED;
30+
}
31+
32+
@Override
33+
public org.neo4j.driver.types.Type type() {
34+
return InternalTypeSystem.TYPE_SYSTEM.UNSUPPORTED();
35+
}
36+
37+
@Override
38+
public UnsupportedType asUnsupportedType() {
39+
return asObject();
40+
}
41+
42+
@Override
43+
public <T> T as(Class<T> targetClass) {
44+
if (targetClass.isAssignableFrom(UnsupportedType.class)) {
45+
return targetClass.cast(asObject());
46+
}
47+
return asMapped(targetClass);
48+
}
49+
}

driver/src/main/java/org/neo4j/driver/internal/value/ValueAdapter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.neo4j.driver.types.Point;
4646
import org.neo4j.driver.types.Relationship;
4747
import org.neo4j.driver.types.Type;
48+
import org.neo4j.driver.types.UnsupportedType;
4849

4950
public abstract class ValueAdapter extends InternalMapAccessorWithDefaultValue implements InternalValue {
5051
@Override
@@ -305,6 +306,11 @@ public Point asPoint() {
305306
throw new Uncoercible(type().name(), "Point");
306307
}
307308

309+
@Override
310+
public UnsupportedType asUnsupportedType() {
311+
throw new Uncoercible(type().name(), "UnsupportedType");
312+
}
313+
308314
@Override
309315
public Value get(int index) {
310316
throw new NotMultiValued(type().name() + " is not an indexed collection");

driver/src/main/java/org/neo4j/driver/types/TypeSystem.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,20 @@ static TypeSystem getDefault() {
164164
*/
165165
@Preview(name = "Neo4j Vector")
166166
Type VECTOR();
167+
168+
/**
169+
* Returns a {@link Type} instance representing an unsupported type.
170+
* <p>
171+
* An unsupported type may occur when a new type is introduced in the Neo4j server and the driver is connected over
172+
* an older Bolt Protocol version that does not support this type. The {@link UnsupportedType} object provides
173+
* information about the unsupported type and the {@link UnsupportedType#minProtocolVersion()} needed to support
174+
* it. However, the {@link UnsupportedType} object itself requires at least Bolt Protocol 6.0.
175+
* <p>
176+
* Note that the unsupported type MUST NOT be sent to the server.
177+
*
178+
* @return the type instance
179+
* @since 6.0.0
180+
* @see UnsupportedType
181+
*/
182+
Type UNSUPPORTED();
167183
}

0 commit comments

Comments
 (0)