From 25d8b84f76f7f0f7f0aacf13959ad2009a9d262d Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Wed, 26 Jul 2023 17:45:46 -0300 Subject: [PATCH 01/10] protocol abstraction begins --- .../edgedb/driver/binary/PacketReader.java | 4 +- .../driver/binary/PacketSerializer.java | 72 +- .../driver/binary/builders/CodecBuilder.java | 157 +-- .../driver/binary/builders/ObjectBuilder.java | 6 +- .../builders/TypeDescriptorBuilder.java | 19 +- .../binary/builders/types/TypeBuilder.java | 7 +- .../builders/types/TypeDeserializerInfo.java | 2 +- .../driver/binary/codecs/ObjectCodec.java | 30 +- .../binary/duplexers/ChannelDuplexer.java | 12 +- .../driver/binary/duplexers/Duplexer.java | 14 +- .../driver/binary/duplexers/HttpDuplexer.java | 16 +- .../ClientMessageType.java | 2 +- .../driver/binary/protocol/ExecuteResult.java | 17 + .../driver/binary/protocol/ParseResult.java | 35 + .../driver/binary/protocol/ProtocolPhase.java | 10 + .../binary/protocol/ProtocolProvider.java | 61 + .../binary/protocol/ProtocolVersion.java | 67 + .../binary/protocol/QueryParameters.java | 39 + .../receivable => protocol}/Receivable.java | 3 +- .../sendables => protocol}/Sendable.java | 4 +- .../ServerMessageType.java | 2 +- .../binary/protocol/TypeDescriptorInfo.java | 24 + .../common}/Annotation.java | 2 +- .../common}/AuthStatus.java | 2 +- .../common}/Cardinality.java | 2 +- .../common}/CompilationFlags.java | 2 +- .../common}/ConnectionParam.java | 2 +- .../common}/DumpObjectDescriptor.java | 2 +- .../common}/DumpTypeInfo.java | 2 +- .../shared => protocol/common}/IOFormat.java | 2 +- .../shared => protocol/common}/KeyValue.java | 2 +- .../binary/protocol/common/ProtocolError.java | 15 + .../common}/ProtocolExtension.java | 2 +- .../protocol/v1/V1ProtocolProvider.java | 854 +++++++++++++ .../v1}/descriptors/ArrayTypeDescriptor.java | 2 +- .../descriptors/BaseScalarTypeDescriptor.java | 2 +- .../v1}/descriptors/DescriptorType.java | 2 +- .../EnumerationTypeDescriptor.java | 2 +- .../v1}/descriptors/InputShapeDescriptor.java | 4 +- .../descriptors/NamedTupleTypeDescriptor.java | 4 +- .../descriptors/ObjectShapeDescriptor.java | 4 +- .../v1}/descriptors/RangeTypeDescriptor.java | 2 +- .../v1}/descriptors/ScalarTypeDescriptor.java | 2 +- .../descriptors/ScalarTypeNameAnnotation.java | 2 +- .../v1}/descriptors/SetTypeDescriptor.java | 2 +- .../v1}/descriptors/TupleTypeDescriptor.java | 2 +- .../descriptors/TypeAnnotationDescriptor.java | 2 +- .../v1}/descriptors/TypeDescriptor.java | 2 +- .../v1}/descriptors/common/ShapeElement.java | 4 +- .../descriptors/common/ShapeElementFlags.java | 2 +- .../v1}/descriptors/common/TupleElement.java | 2 +- .../v1/receivables}/AuthenticationStatus.java | 7 +- .../v1/receivables}/CommandComplete.java | 7 +- .../receivables}/CommandDataDescription.java | 9 +- .../v1/receivables}/Data.java | 5 +- .../v1/receivables}/DumpBlock.java | 7 +- .../v1/receivables}/DumpHeader.java | 11 +- .../v1/receivables}/ErrorResponse.java | 48 +- .../v1/receivables}/LogMessage.java | 7 +- .../v1/receivables}/ParameterStatus.java | 5 +- .../v1/receivables}/ReadyForCommand.java | 7 +- .../v1/receivables}/RestoreReady.java | 7 +- .../v1/receivables}/ServerHandshake.java | 7 +- .../v1/receivables}/ServerKeyData.java | 5 +- .../v1/receivables}/StateDataDescription.java | 5 +- .../AuthenticationSASLInitialResponse.java | 5 +- .../sendables/AuthenticationSASLResponse.java | 5 +- .../v1}/sendables/ClientHandshake.java | 9 +- .../v1}/sendables/Dump.java | 7 +- .../v1}/sendables/Execute.java | 11 +- .../v1}/sendables/Parse.java | 11 +- .../v1}/sendables/Restore.java | 9 +- .../v1}/sendables/RestoreBlock.java | 5 +- .../v1}/sendables/RestoreEOF.java | 7 +- .../v1}/sendables/Sync.java | 7 +- .../v1}/sendables/Terminate.java | 7 +- .../driver/clients/EdgeDBBinaryClient.java | 1097 ++++------------- .../driver/clients/EdgeDBHttpClient.java | 4 +- .../driver/clients/EdgeDBTCPClient.java | 6 +- .../java/com/edgedb/driver/util/Scram.java | 6 +- .../test/java/shared/SharedTestsRunner.java | 35 +- .../models/QueryExecutionArguments.java | 2 +- 82 files changed, 1726 insertions(+), 1178 deletions(-) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol}/ClientMessageType.java (94%) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/ExecuteResult.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/ParseResult.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolPhase.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/QueryParameters.java rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol}/Receivable.java (86%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/sendables => protocol}/Sendable.java (89%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol}/ServerMessageType.java (93%) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/Annotation.java (95%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/AuthStatus.java (90%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/Cardinality.java (90%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/CompilationFlags.java (90%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/ConnectionParam.java (94%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/DumpObjectDescriptor.java (93%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/DumpTypeInfo.java (89%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/IOFormat.java (89%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/KeyValue.java (95%) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ProtocolError.java rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/shared => protocol/common}/ProtocolExtension.java (95%) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/ArrayTypeDescriptor.java (92%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/BaseScalarTypeDescriptor.java (85%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/DescriptorType.java (93%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/EnumerationTypeDescriptor.java (90%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/InputShapeDescriptor.java (80%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/NamedTupleTypeDescriptor.java (81%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/ObjectShapeDescriptor.java (80%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/RangeTypeDescriptor.java (89%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/ScalarTypeDescriptor.java (90%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/ScalarTypeNameAnnotation.java (89%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/SetTypeDescriptor.java (89%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/TupleTypeDescriptor.java (91%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/TypeAnnotationDescriptor.java (91%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/TypeDescriptor.java (57%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/common/ShapeElement.java (84%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/common/ShapeElementFlags.java (88%) rename src/driver/src/main/java/com/edgedb/driver/binary/{ => protocol/v1}/descriptors/common/TupleElement.java (84%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/AuthenticationStatus.java (85%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/CommandComplete.java (83%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/CommandDataDescription.java (84%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/Data.java (82%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/DumpBlock.java (69%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/DumpHeader.java (76%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/ErrorResponse.java (58%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/LogMessage.java (79%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/ParameterStatus.java (80%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/ReadyForCommand.java (72%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/RestoreReady.java (69%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/ServerHandshake.java (74%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/ServerKeyData.java (78%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets/receivable => protocol/v1/receivables}/StateDataDescription.java (82%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/AuthenticationSASLInitialResponse.java (84%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/AuthenticationSASLResponse.java (81%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/ClientHandshake.java (83%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/Dump.java (75%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/Execute.java (89%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/Parse.java (87%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/Restore.java (79%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/RestoreBlock.java (81%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/RestoreEOF.java (57%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/Sync.java (57%) rename src/driver/src/main/java/com/edgedb/driver/binary/{packets => protocol/v1}/sendables/Terminate.java (58%) diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java b/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java index 0e4be577..2aff8caf 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java @@ -2,8 +2,8 @@ import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.codecs.CodecContext; -import com.edgedb.driver.binary.packets.shared.Annotation; -import com.edgedb.driver.binary.packets.shared.KeyValue; +import com.edgedb.driver.binary.protocol.common.Annotation; +import com.edgedb.driver.binary.protocol.common.KeyValue; import com.edgedb.driver.exceptions.EdgeDBException; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/PacketSerializer.java b/src/driver/src/main/java/com/edgedb/driver/binary/PacketSerializer.java index 943e7c30..e97ae852 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/PacketSerializer.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/PacketSerializer.java @@ -1,8 +1,9 @@ package com.edgedb.driver.binary; -import com.edgedb.driver.binary.packets.ServerMessageType; -import com.edgedb.driver.binary.packets.receivable.*; -import com.edgedb.driver.binary.packets.sendables.Sendable; +import com.edgedb.driver.binary.protocol.ServerMessageType; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.ConnectionFailedException; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.util.HexUtils; @@ -24,33 +25,12 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; -import java.util.function.Function; import java.util.stream.Collectors; public class PacketSerializer { private static final Logger logger = LoggerFactory.getLogger(PacketSerializer.class); - private static final @NotNull Map> deserializerMap; private static final Map, Map>> binaryEnumMap = new HashMap<>(); - static { - deserializerMap = new HashMap<>(); - - deserializerMap.put(ServerMessageType.AUTHENTICATION, AuthenticationStatus::new); - deserializerMap.put(ServerMessageType.COMMAND_COMPLETE, CommandComplete::new); - deserializerMap.put(ServerMessageType.COMMAND_DATA_DESCRIPTION, CommandDataDescription::new); - deserializerMap.put(ServerMessageType.DATA, Data::new); - deserializerMap.put(ServerMessageType.DUMP_BLOCK, DumpBlock::new); - deserializerMap.put(ServerMessageType.DUMP_HEADER, DumpHeader::new); - deserializerMap.put(ServerMessageType.ERROR_RESPONSE, ErrorResponse::new); - deserializerMap.put(ServerMessageType.LOG_MESSAGE, LogMessage::new); - deserializerMap.put(ServerMessageType.PARAMETER_STATUS, ParameterStatus::new); - deserializerMap.put(ServerMessageType.READY_FOR_COMMAND, ReadyForCommand::new); - deserializerMap.put(ServerMessageType.RESTORE_READY, RestoreReady::new); - deserializerMap.put(ServerMessageType.SERVER_HANDSHAKE, ServerHandshake::new); - deserializerMap.put(ServerMessageType.SERVER_KEY_DATA, ServerKeyData::new); - deserializerMap.put(ServerMessageType.STATE_DATA_DESCRIPTION, StateDataDescription::new); - } - public static & BinaryEnum, U extends Number> void registerBinaryEnum(Class cls, T @NotNull [] values) { binaryEnumMap.put(cls, Arrays.stream(values).collect(Collectors.toMap(BinaryEnum::getValue, v -> v))); } @@ -64,7 +44,7 @@ public static & BinaryEnum, U extends Number> T getEnumVal return (T)binaryEnumMap.get(enumCls).get(raw); } - public static @NotNull MessageToMessageDecoder createDecoder() { + public static @NotNull MessageToMessageDecoder createDecoder(EdgeDBBinaryClient client) { return new MessageToMessageDecoder<>() { private final Map contracts = new HashMap<>(); @@ -96,7 +76,7 @@ protected void decode(@NotNull ChannelHandlerContext ctx, @NotNull ByteBuf msg, // can we read this packet? if (msg.readableBytes() >= length) { - var packet = PacketSerializer.deserialize(type, length, msg.readSlice((int) length)); + var packet = PacketSerializer.deserialize(client, type, length, msg.readSlice((int) length)); if(packet == null) { logger.error("Got null result for packet type {}", type); @@ -175,7 +155,7 @@ public boolean tryComplete(@NotNull ByteBuf other) { if (data.readableBytes() >= length) { // read - packet = PacketSerializer.deserialize(messageType, length, data, false); + packet = PacketSerializer.deserialize(client, messageType, length, data, false); return true; } @@ -218,42 +198,36 @@ protected void encode(@NotNull ChannelHandlerContext ctx, @NotNull Sendable msg, } public static @Nullable Receivable deserialize( - ServerMessageType messageType, long length, @NotNull ByteBuf buffer + EdgeDBBinaryClient client, ServerMessageType messageType, long length, @NotNull ByteBuf buffer ) { var reader = new PacketReader(buffer); - return deserializeSingle(messageType, length, reader, true); + return deserializeSingle(client, messageType, length, reader, true); } public static @Nullable Receivable deserialize( - ServerMessageType messageType, long length, @NotNull ByteBuf buffer, boolean verifyEmpty + EdgeDBBinaryClient client, ServerMessageType messageType, long length, @NotNull ByteBuf buffer, boolean verifyEmpty ) { var reader = new PacketReader(buffer); - return deserializeSingle(messageType, length, reader, verifyEmpty); + return deserializeSingle(client, messageType, length, reader, verifyEmpty); } - public static @Nullable Receivable deserializeSingle(PacketReader reader) { + public static @Nullable Receivable deserializeSingle(EdgeDBBinaryClient client, PacketReader reader) { var messageType = reader.readEnum(ServerMessageType.class, Byte.TYPE); var length = reader.readUInt32().longValue(); - return deserializeSingle(messageType, length, reader, false); + return deserializeSingle(client, messageType, length, reader, false); } public static @Nullable Receivable deserializeSingle( - ServerMessageType type, long length, @NotNull PacketReader reader, + EdgeDBBinaryClient client, ServerMessageType type, long length, @NotNull PacketReader reader, boolean verifyEmpty ) { - if(!deserializerMap.containsKey(type)) { - logger.error("Unknown packet type {}", type); - reader.skip(length); - return null; - } - try { - return deserializerMap.get(type).apply(reader); + return client.getProtocolProvider().readPacket(type, (int)length, reader); } catch (Exception x) { logger.error("Failed to deserialize packet", x); - throw x; + return null; } finally { // ensure we read the entire packet @@ -263,9 +237,15 @@ protected void encode(@NotNull ChannelHandlerContext ctx, @NotNull Sendable msg, } } - public static HttpResponse.BodyHandler> PACKET_BODY_HANDLER = new PacketBodyHandler(); - + public static HttpResponse.BodyHandler> createHandler(EdgeDBBinaryClient client) { + return new PacketBodyHandler(client); + } private static class PacketBodyHandler implements HttpResponse.BodyHandler> { + private final EdgeDBBinaryClient client; + public PacketBodyHandler(EdgeDBBinaryClient client) { + this.client = client; + } + @Override public HttpResponse.BodySubscriber> apply(HttpResponse.ResponseInfo responseInfo) { // ensure success @@ -276,7 +256,7 @@ public HttpResponse.BodySubscriber> apply(HttpResponse.Response : new PacketBodySubscriber(responseInfo.statusCode()); } - private static class PacketBodySubscriber implements HttpResponse.BodySubscriber> { + private class PacketBodySubscriber implements HttpResponse.BodySubscriber> { private final @Nullable List<@NotNull ByteBuf> buffers; private final CompletableFuture> promise; @@ -334,7 +314,7 @@ public void onComplete() { var data = new ArrayList(); while(completeBuffer.readableBytes() > 0) { - var packet = deserializeSingle(reader); + var packet = deserializeSingle(client, reader); if(packet == null && completeBuffer.readableBytes() > 0) { promise.completeExceptionally( diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java index 2269c2f5..be803465 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java @@ -1,17 +1,17 @@ package com.edgedb.driver.binary.builders; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.codecs.*; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.codecs.NullCodec; import com.edgedb.driver.binary.codecs.scalars.*; import com.edgedb.driver.binary.codecs.scalars.complex.BytesCodec; import com.edgedb.driver.binary.codecs.scalars.complex.DateTimeCodec; import com.edgedb.driver.binary.codecs.scalars.complex.RelativeDurationCodec; -import com.edgedb.driver.binary.descriptors.*; -import com.edgedb.driver.binary.packets.shared.Cardinality; -import com.edgedb.driver.binary.packets.shared.IOFormat; -import com.edgedb.driver.datatypes.Range; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.IOFormat; +import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.EdgeDBException; -import com.edgedb.driver.exceptions.MissingCodecException; import com.edgedb.driver.util.CollectionUtils; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; @@ -20,7 +20,6 @@ import org.slf4j.LoggerFactory; import javax.naming.OperationNotSupportedException; -import java.lang.reflect.Array; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -74,122 +73,64 @@ public final class CodecBuilder { return (Codec) buildCodec(id, reader); } @SuppressWarnings("unchecked") - public static @NotNull Codec buildCodec(@NotNull UUID id, @NotNull PacketReader reader) throws EdgeDBException { + public static @NotNull Codec buildCodec(EdgeDBBinaryClient client, @NotNull UUID id, @NotNull PacketReader reader) throws EdgeDBException { try { if(id.equals(NULL_CODEC_ID)) { return getOrCreateCodec(id, NullCodec::new); } - List> codecs = new ArrayList<>(); + var descriptors = new ArrayList>(); while(!reader.isEmpty()) { var start = reader.position(); - var descriptor = TypeDescriptorBuilder.getDescriptor(reader); + var descriptor = client.getProtocolProvider().readDescriptor(reader); var end = reader.position(); logger.trace("{}/{}: read {}, size {}", end, reader.size(), descriptor.type, end-start); - Codec codec; - - if(codecCache.containsKey(descriptor.getId())) { - codec = codecCache.get(descriptor.getId()); - } else { - codec = getScalarCodec(descriptor.getId()); - } - - if(codec != null) { - codecs.add(codec); - continue; - } - - switch (descriptor.type) { - case ARRAY_TYPE_DESCRIPTOR: - var arrayType = descriptor.as(ArrayTypeDescriptor.class); - - codec = getOrCreateCodec(descriptor.getId(), () -> - new CompilableCodec( - codecs.get(arrayType.typePosition.intValue()), - ArrayCodec::new, - t -> Array.newInstance(t,0).getClass() - ) - ); - break; - case SCALAR_TYPE_DESCRIPTOR: - case BASE_SCALAR_TYPE_DESCRIPTOR: - // should be resolved by the above case, getting here is an error - throw new MissingCodecException(String.format("Could not find the scalar type %s", descriptor.getId().toString())); - case ENUMERATION_TYPE_DESCRIPTOR: - codec = getOrCreateCodec(descriptor.getId(), TextCodec::new); - break; - case INPUT_SHAPE_DESCRIPTOR: - var inputShape = descriptor.as(InputShapeDescriptor.class); - var inputShapeCodecs = new Codec[inputShape.shapes.length]; - var inputShapeNames = new String[inputShape.shapes.length]; - - for (int i = 0; i != inputShape.shapes.length; i++) { - inputShapeCodecs[i] = codecs.get(inputShape.shapes[i].typePosition.intValue()); - inputShapeNames[i] = inputShape.shapes[i].name; - } - - codec = getOrCreateCodec(descriptor.getId(), () -> new SparseObjectCodec(inputShapeCodecs, inputShapeNames)); - break; - - - case TUPLE_TYPE_DESCRIPTOR: - var tupleType = descriptor.as(TupleTypeDescriptor.class); - var innerCodecs = new Codec[tupleType.elementTypeDescriptorPositions.length]; - - for(int i = 0; i != innerCodecs.length; i++) { - innerCodecs[i] = codecs.get(tupleType.elementTypeDescriptorPositions[i].intValue()); - } - - codec = getOrCreateCodec(descriptor.getId(), () -> new TupleCodec(innerCodecs)); - break; - case NAMED_TUPLE_DESCRIPTOR: - var tupleShape = descriptor.as(NamedTupleTypeDescriptor.class); - codec = getOrCreateCodec(descriptor.getId(), () -> ObjectCodec.create(codecs::get, tupleShape.elements)); - break; - case OBJECT_SHAPE_DESCRIPTOR: - var objectShape = descriptor.as(ObjectShapeDescriptor.class); - codec = getOrCreateCodec(descriptor.getId(), () -> ObjectCodec.create(codecs::get, objectShape.shapes)); - break; - case RANGE_TYPE_DESCRIPTOR: - var rangeType = descriptor.as(RangeTypeDescriptor.class); - - codec = getOrCreateCodec(descriptor.getId(), () -> - new CompilableCodec( - codecs.get(rangeType.typePosition.intValue()), - RangeCodec::new, - t -> Range.empty(t).getClass() - ) - ); - break; - case SCALAR_TYPE_NAME_ANNOTATION: - // ignored - break; - case SET_DESCRIPTOR: - var setTypes = descriptor.as(SetTypeDescriptor.class); - - codec = getOrCreateCodec(descriptor.getId(), () -> - new CompilableCodec( - codecs.get(setTypes.typePosition.intValue()), - SetCodec::new, - t -> Array.newInstance(t, 0).getClass() - ) - ); - break; - default: - throw new MissingCodecException(String.format("Could not find a type descriptor with the type %s", descriptor.getId().toString())); - } - - codecs.add(codec); + descriptors.add(descriptor); } - var finalCodec = CollectionUtils.last(codecs); + var codecs = new ArrayList>(); - codecCache.putIfAbsent(id, finalCodec); + for(var i = 0; i != descriptors.size(); i++) { - return finalCodec; + } + + //List> codecs = new ArrayList<>(); +// +// while(!reader.isEmpty()) { +// var start = reader.position(); +// var descriptor = TypeDescriptorBuilder.getDescriptor(reader); +// var end = reader.position(); +// +// logger.trace("{}/{}: read {}, size {}", end, reader.size(), descriptor.type, end-start); +// +// Codec codec; +// +// if(codecCache.containsKey(descriptor.getId())) { +// codec = codecCache.get(descriptor.getId()); +// } else { +// codec = getScalarCodec(descriptor.getId()); +// } +// +// if(codec != null) { +// codecs.add(codec); +// continue; +// } +// +// switch (descriptor.type) { +// +// } +// +// codecs.add(codec); +// } +// +// var finalCodec = CollectionUtils.last(codecs); +// +// codecCache.putIfAbsent(id, finalCodec); +// +// return finalCodec; } catch (Throwable x) { logger.error("Failed to build codec", x); @@ -236,7 +177,7 @@ public static void updateCachedCodecs(long cacheKey, UUID inCodecId, UUID outCod } @SuppressWarnings("unchecked") - private static Codec getOrCreateCodec(UUID id, @NotNull Supplier> constructor) { + public static Codec getOrCreateCodec(UUID id, @NotNull Supplier> constructor) { return (Codec) codecPartsInstanceCache.computeIfAbsent(id, v -> constructor.get()); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/ObjectBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/ObjectBuilder.java index cc97c45c..7b946756 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/ObjectBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/ObjectBuilder.java @@ -4,9 +4,9 @@ import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.codecs.ObjectCodec; import com.edgedb.driver.binary.codecs.visitors.TypeVisitor; -import com.edgedb.driver.binary.packets.receivable.Data; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.EdgeDBException; +import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,7 +30,7 @@ public interface CollectionConverter> { }}; } - public static @Nullable T buildResult(@NotNull EdgeDBBinaryClient client, Codec codec, @NotNull Data data, @NotNull Class cls) throws EdgeDBException, OperationNotSupportedException { + public static @Nullable T buildResult(@NotNull EdgeDBBinaryClient client, Codec codec, @NotNull ByteBuf data, @NotNull Class cls) throws EdgeDBException, OperationNotSupportedException { var visitor = new TypeVisitor(client); visitor.setTargetType(cls); codec = visitor.visit(codec); @@ -39,7 +39,7 @@ public interface CollectionConverter> { return TypeBuilder.buildObject(client, cls, (ObjectCodec)codec, data); } - var value = Codec.deserializeFromBuffer(codec, Objects.requireNonNull(data.payloadBuffer), client.getCodecContext()); + var value = Codec.deserializeFromBuffer(codec, Objects.requireNonNull(data), client.getCodecContext()); return convertTo(cls, value); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java index 65c2f723..1ed0287d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java @@ -1,7 +1,7 @@ package com.edgedb.driver.binary.builders; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.descriptors.*; +import com.edgedb.driver.binary.protocol.v1.descriptors.*; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.NotNull; @@ -19,17 +19,7 @@ public final class TypeDescriptorBuilder { static { typeDescriptorFactories = new HashMap<>() { { - put(DescriptorType.ARRAY_TYPE_DESCRIPTOR, ArrayTypeDescriptor::new); - put(DescriptorType.BASE_SCALAR_TYPE_DESCRIPTOR, BaseScalarTypeDescriptor::new); - put(DescriptorType.ENUMERATION_TYPE_DESCRIPTOR, EnumerationTypeDescriptor::new); - put(DescriptorType.NAMED_TUPLE_DESCRIPTOR, NamedTupleTypeDescriptor::new); - put(DescriptorType.OBJECT_SHAPE_DESCRIPTOR, ObjectShapeDescriptor::new); - put(DescriptorType.SCALAR_TYPE_DESCRIPTOR, ScalarTypeDescriptor::new); - put(DescriptorType.SCALAR_TYPE_NAME_ANNOTATION, ScalarTypeNameAnnotation::new); - put(DescriptorType.SET_DESCRIPTOR, SetTypeDescriptor::new); - put(DescriptorType.TUPLE_TYPE_DESCRIPTOR, TupleTypeDescriptor::new); - put(DescriptorType.INPUT_SHAPE_DESCRIPTOR, InputShapeDescriptor::new); - put(DescriptorType.RANGE_TYPE_DESCRIPTOR, RangeTypeDescriptor::new); + } }; } @@ -65,10 +55,5 @@ public TypeDescriptorResult(DescriptorType type, TypeDescriptor descriptor) { public UUID getId() { return descriptor.getId(); } - - @SuppressWarnings("unchecked") - public T as(Class ignored) { - return (T)descriptor; - } } } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeBuilder.java index f574fb72..3acaaa4a 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeBuilder.java @@ -3,17 +3,16 @@ import com.edgedb.driver.annotations.EdgeDBType; import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.codecs.ObjectCodec; -import com.edgedb.driver.binary.packets.receivable.Data; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.datatypes.Tuple; import com.edgedb.driver.datatypes.internal.TupleImpl; import com.edgedb.driver.exceptions.EdgeDBException; +import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -30,7 +29,7 @@ public final class TypeBuilder { } @SuppressWarnings("unchecked") - public static @Nullable T buildObject(@NotNull EdgeDBBinaryClient client, @NotNull Class type, ObjectCodec codec, @NotNull Data data) throws OperationNotSupportedException, EdgeDBException { + public static @Nullable T buildObject(@NotNull EdgeDBBinaryClient client, @NotNull Class type, ObjectCodec codec, @NotNull ByteBuf data) throws OperationNotSupportedException, EdgeDBException { var info = getDeserializerInfo(type); if(info == null) { @@ -42,7 +41,7 @@ public final class TypeBuilder { } - return (T) Codec.deserializeFromBuffer(codec, Objects.requireNonNull(data.payloadBuffer), client.getCodecContext()); + return (T) Codec.deserializeFromBuffer(codec, data, client.getCodecContext()); } @SuppressWarnings("unchecked") diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java index f66365ba..0b68fac6 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java @@ -5,7 +5,7 @@ import com.edgedb.driver.ObjectEnumerator; import com.edgedb.driver.binary.builders.TypeDeserializerFactory; import com.edgedb.driver.binary.builders.internal.ObjectEnumeratorImpl; -import com.edgedb.driver.binary.packets.shared.Cardinality; +import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.namingstrategies.NamingStrategy; import com.edgedb.driver.util.FastInverseIndexer; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java index 284e3cc7..761209a9 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java @@ -5,9 +5,9 @@ import com.edgedb.driver.binary.builders.internal.ObjectEnumeratorImpl; import com.edgedb.driver.binary.builders.types.TypeBuilder; import com.edgedb.driver.binary.builders.types.TypeDeserializerInfo; -import com.edgedb.driver.binary.descriptors.common.ShapeElement; -import com.edgedb.driver.binary.descriptors.common.TupleElement; -import com.edgedb.driver.binary.packets.shared.Cardinality; +import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; +import com.edgedb.driver.binary.protocol.v1.descriptors.common.TupleElement; +import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.exceptions.NoTypeConverterException; import org.jetbrains.annotations.NotNull; @@ -21,6 +21,9 @@ @SuppressWarnings("rawtypes") public class ObjectCodec extends CodecBase implements ArgumentCodec { + public static ObjectProperty propertyOf(String name, Cardinality cardinality, Codec codec) { + return new ObjectProperty(name, codec, cardinality); + } public static final class TypeInitializedObjectCodec extends ObjectCodec { private final @Nullable TypeDeserializerInfo deserializer; @@ -73,34 +76,33 @@ public Class getTarget() { } } - public static final class Element { + public static final class ObjectProperty { public final String name; public final @Nullable Cardinality cardinality; public Codec codec; - public Element(String name, Codec codec, @Nullable Cardinality cardinality) { + public ObjectProperty(String name, Codec codec, @Nullable Cardinality cardinality) { this.name = name; this.codec = codec; this.cardinality = cardinality; } } - public final Element[] elements; + public final ObjectProperty[] elements; private final @NotNull ConcurrentMap, TypeInitializedObjectCodec> typeCodecs; - private final Object lock = new Object(); - public ObjectCodec(Element... elements) { + public ObjectCodec(ObjectProperty... elements) { super(Object.class); this.elements = elements; this.typeCodecs = new ConcurrentHashMap<>(); } public static @NotNull ObjectCodec create(@NotNull Function> fetchCodec, ShapeElement @NotNull [] shape) { - var elements = new Element[shape.length]; + var elements = new ObjectProperty[shape.length]; for (int i = 0; i < shape.length; i++) { var shapeElement = shape[i]; - elements[i] = new Element( + elements[i] = new ObjectProperty( shapeElement.name, fetchCodec.apply(shapeElement.typePosition.intValue()), shapeElement.cardinality @@ -110,15 +112,15 @@ public ObjectCodec(Element... elements) { return new ObjectCodec(elements); } - public static @NotNull ObjectCodec create(@NotNull Function> fetchCodec, TupleElement @NotNull [] shape) { - var elements = new Element[shape.length]; + public static @NotNull ObjectCodec create(@NotNull Function> fetchCodec, TupleElement @NotNull [] shape) { + var elements = new ObjectProperty[shape.length]; for (int i = 0; i < shape.length; i++) { var shapeElement = shape[i]; - elements[i] = new Element( + elements[i] = new ObjectProperty( shapeElement.name, - fetchCodec.apply(shapeElement.typePosition), + fetchCodec.apply((int)shapeElement.typePosition), null ); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java index 3a719b3c..d88f83fa 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java @@ -1,9 +1,10 @@ package com.edgedb.driver.binary.duplexers; import com.edgedb.driver.async.ChannelCompletableFuture; -import com.edgedb.driver.binary.packets.receivable.Receivable; -import com.edgedb.driver.binary.packets.sendables.Sendable; -import com.edgedb.driver.binary.packets.sendables.Terminate; +import com.edgedb.driver.binary.protocol.ProtocolProvider; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.binary.protocol.v1.sendables.Terminate; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.ConnectionFailedException; import com.edgedb.driver.exceptions.ConnectionFailedTemporarilyException; @@ -154,6 +155,11 @@ public ChannelDuplexer(EdgeDBBinaryClient client) { this.readPromises = new ArrayDeque<>(); } + @Override + public ProtocolProvider getProtocolProvider() { + return client.getProtocolProvider(); + } + @Override public @NotNull CompletionStage readNext() { logger.debug("Entering message queue lock"); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/Duplexer.java b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/Duplexer.java index 31de5c74..94de4585 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/Duplexer.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/Duplexer.java @@ -1,20 +1,20 @@ package com.edgedb.driver.binary.duplexers; -import com.edgedb.driver.binary.packets.receivable.Receivable; -import com.edgedb.driver.binary.packets.sendables.Sendable; -import com.edgedb.driver.binary.packets.sendables.Sync; +import com.edgedb.driver.binary.protocol.ProtocolProvider; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.Sendable; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; -import javax.net.ssl.SSLException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.function.BiFunction; import java.util.function.Function; public abstract class Duplexer { + public abstract ProtocolProvider getProtocolProvider(); public abstract void reset(); public abstract boolean isConnected(); @@ -42,7 +42,11 @@ public final CompletionStage duplexAndSync( @NotNull Sendable packet, DuplexCallback func ) { - return duplex(func, packet, new Sync()); + return duplex(func, packet, getProtocolProvider().sync()); + } + + public final CompletionStage duplexSingle(Sendable packet) { + return send(packet).thenCompose(v -> readNext()); } @FunctionalInterface diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/HttpDuplexer.java b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/HttpDuplexer.java index b776d149..a788d63e 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/HttpDuplexer.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/HttpDuplexer.java @@ -1,8 +1,9 @@ package com.edgedb.driver.binary.duplexers; import com.edgedb.driver.binary.PacketSerializer; -import com.edgedb.driver.binary.packets.receivable.Receivable; -import com.edgedb.driver.binary.packets.sendables.Sendable; +import com.edgedb.driver.binary.protocol.ProtocolProvider; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.Sendable; import com.edgedb.driver.clients.EdgeDBHttpClient; import com.edgedb.driver.exceptions.ConnectionFailedException; import com.edgedb.driver.exceptions.EdgeDBException; @@ -14,7 +15,9 @@ import javax.naming.OperationNotSupportedException; import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.ArrayDeque; +import java.util.List; import java.util.Objects; import java.util.Queue; import java.util.concurrent.*; @@ -30,8 +33,10 @@ public class HttpDuplexer extends Duplexer { private final Executor lockExecutor; private final Queue<@NotNull Receivable> packetQueue; private final Queue> readPromises; + private final HttpResponse.BodyHandler> bodyHandler; public HttpDuplexer(EdgeDBHttpClient client) { + bodyHandler = PacketSerializer.createHandler(client); this.client = client; this.lock = new Semaphore(1); this.lockExecutor = Executors.newSingleThreadExecutor(); @@ -39,6 +44,11 @@ public HttpDuplexer(EdgeDBHttpClient client) { this.readPromises = new ArrayDeque<>(); } + @Override + public ProtocolProvider getProtocolProvider() { + return client.getProtocolProvider(); + } + @Override public void reset() { packetQueue.clear(); @@ -122,7 +132,7 @@ private CompletionStage send0(Sendable packet, @Nullable Sendable... packe ) .thenCompose((request) -> { logger.debug("Sending execution request..."); - return client.httpClient.sendAsync(request, PacketSerializer.PACKET_BODY_HANDLER); + return client.httpClient.sendAsync(request, bodyHandler); }) .thenCompose(EdgeDBHttpClient::ensureSuccess) .thenAccept(response -> { diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/ClientMessageType.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ClientMessageType.java similarity index 94% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/ClientMessageType.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/ClientMessageType.java index 01532bc8..9eb582cc 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/ClientMessageType.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ClientMessageType.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets; +package com.edgedb.driver.binary.protocol; public enum ClientMessageType { AUTHENTICATION_SASL_INITIAL_RESPONSE (0x70), diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ExecuteResult.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ExecuteResult.java new file mode 100644 index 00000000..a8a1fe8e --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ExecuteResult.java @@ -0,0 +1,17 @@ +package com.edgedb.driver.binary.protocol; + +import com.edgedb.driver.binary.codecs.Codec; +import io.netty.buffer.ByteBuf; + +import java.util.List; + +public class ExecuteResult { + public final Codec codec; + public final List data; + + + public ExecuteResult(Codec codec, List data) { + this.codec = codec; + this.data = data; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ParseResult.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ParseResult.java new file mode 100644 index 00000000..2f4d13c4 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ParseResult.java @@ -0,0 +1,35 @@ +package com.edgedb.driver.binary.protocol; + +import com.edgedb.driver.Capabilities; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import io.netty.buffer.ByteBuf; + +import java.util.EnumSet; +import java.util.UUID; + +public final class ParseResult { + public final Codec inCodec; + public final Codec outCodec; + + public final UUID inCodecId; + public final UUID outCodecId; + public final ByteBuf stateData; + + public final EnumSet capabilities; + public final Cardinality cardinality; + + + public ParseResult( + Codec inCodec, Codec outCodec, UUID inCodecId, UUID outCodecId, ByteBuf stateData, EnumSet capabilities, + Cardinality cardinality + ) { + this.inCodec = inCodec; + this.outCodec = outCodec; + this.inCodecId = inCodecId; + this.outCodecId = outCodecId; + this.stateData = stateData; + this.capabilities = capabilities; + this.cardinality = cardinality; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolPhase.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolPhase.java new file mode 100644 index 00000000..fabd03d0 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolPhase.java @@ -0,0 +1,10 @@ +package com.edgedb.driver.binary.protocol; + +public enum ProtocolPhase { + CONNECTION, + AUTH, + COMMAND, + DUMP, + TERMINATION, + ERRORED; +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java new file mode 100644 index 00000000..92f203f0 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java @@ -0,0 +1,61 @@ +package com.edgedb.driver.binary.protocol; + +import com.edgedb.driver.EdgeDBConnection; +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.v1.V1ProtocolProvider; +import com.edgedb.driver.binary.protocol.v1.descriptors.TypeDescriptor; +import com.edgedb.driver.clients.EdgeDBBinaryClient; +import com.edgedb.driver.exceptions.MissingCodecException; +import com.edgedb.driver.exceptions.UnexpectedMessageException; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +public interface ProtocolProvider { + @Nullable ProtocolProvider DEFAULT_PROVIDER = null; + + ConcurrentMap> PROVIDERS_FACTORY = new ConcurrentHashMap<>(); + Map> PROVIDERS = new HashMap<>(){{ + put(ProtocolVersion.of(1, 0), V1ProtocolProvider::new); + }}; + + static ProtocolProvider getProvider(EdgeDBBinaryClient client) { + return PROVIDERS_FACTORY.computeIfAbsent( + client.getConnectionArguments(), + ignored -> PROVIDERS.get(ProtocolVersion.BINARY_PROTOCOL_DEFAULT_VERSION) + ).apply(client); + } + + static void updateProviderFor(EdgeDBBinaryClient client, ProtocolProvider provider) { + PROVIDERS_FACTORY.put(client.getConnectionArguments(), PROVIDERS.get(provider.getVersion())); + } + + + ProtocolVersion getVersion(); + ProtocolPhase getPhase(); + Map getServerConfig(); + + Receivable readPacket(ServerMessageType type, int length, PacketReader reader) throws UnexpectedMessageException; + TypeDescriptorInfo> readDescriptor(PacketReader reader) throws UnexpectedMessageException; + > @Nullable Codec buildCodec( + TypeDescriptorInfo descriptor, + Function> getRelativeCodec, Function getRelativeDescriptor + ) throws MissingCodecException; + + + CompletionStage parseQuery(QueryParameters queryParameters); + CompletionStage executeQuery(QueryParameters queryParameters, ParseResult parseResult); + + CompletionStage sendSyncMessage(); + CompletionStage processMessage(Receivable packet); + + Sendable handshake(); + Sendable terminate(); + Sendable sync(); +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java new file mode 100644 index 00000000..6d3de0a7 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java @@ -0,0 +1,67 @@ +package com.edgedb.driver.binary.protocol; + + +import org.joou.UShort; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public final class ProtocolVersion { + public static final ProtocolVersion BINARY_PROTOCOL_DEFAULT_VERSION = of(1, 0); + + private static final ConcurrentMap VERSIONS = new ConcurrentHashMap<>() {{ + put(keyOf(1, 0), new ProtocolVersion(1, 0)); + put(keyOf(2, 0), new ProtocolVersion(2, 0)); + }}; + + public final short major; + public final short minor; + + private ProtocolVersion(int major, int minor) { + this.major = (short)(major & 0xFFFF); + this.minor = (short)(minor & 0xFFFF); + } + + private ProtocolVersion(int version) { + this.major = (short)((version >> 16) & 0xFFFF); + this.minor = (short)(version & 0xFFFF); + } + + public static ProtocolVersion of(int major, int minor) { + return VERSIONS != null + ? VERSIONS.computeIfAbsent(keyOf(major, minor), ProtocolVersion::new) + : new ProtocolVersion(major, minor); + } + + public static ProtocolVersion of(UShort major, UShort minor) { + return of(major.intValue(), minor.intValue()); + } + + private static int keyOf(int major, int minor) { + return ((major & 0xFFFF) << 16) + (minor & 0xFFFF); + } + + public boolean equals(UShort major, UShort minor) { + return equals(major.intValue(), minor.intValue()); + } + + public boolean equals(int major, int minor) { + return this.major == major && this.minor == minor; + } + + @Override + public String toString() { + return String.format("%d.%d", major, minor); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof ProtocolVersion)) { + return super.equals(obj); + } + + var other = (ProtocolVersion)obj; + + return this.major == other.major && this.minor == other.minor; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/QueryParameters.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/QueryParameters.java new file mode 100644 index 00000000..64029210 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/QueryParameters.java @@ -0,0 +1,39 @@ +package com.edgedb.driver.binary.protocol; + +import com.edgedb.driver.Capabilities; +import com.edgedb.driver.binary.builders.CodecBuilder; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.IOFormat; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumSet; +import java.util.Map; + +public final class QueryParameters { + public final String query; + public final @Nullable Map arguments; + public final EnumSet capabilities; + public final Cardinality cardinality; + public final IOFormat format; + public final boolean implicitTypeNames; + + public QueryParameters( + String query, + @Nullable Map arguments, + EnumSet capabilities, + Cardinality cardinality, + IOFormat format, + boolean implicitTypeNames + ) { + this.query = query; + this.arguments = arguments; + this.capabilities = capabilities; + this.cardinality = cardinality; + this.format = format; + this.implicitTypeNames = implicitTypeNames; + } + + public long getCacheKey() { + return CodecBuilder.getCacheKey(query, cardinality, format); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/Receivable.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/Receivable.java similarity index 86% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/Receivable.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/Receivable.java index 36668057..bc709635 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/Receivable.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/Receivable.java @@ -1,6 +1,5 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol; -import com.edgedb.driver.binary.packets.ServerMessageType; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Sendable.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/Sendable.java similarity index 89% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Sendable.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/Sendable.java index 443aacbd..80b68665 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Sendable.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/Sendable.java @@ -1,8 +1,8 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.SerializableData; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.ClientMessageType; import org.jetbrains.annotations.NotNull; import javax.naming.OperationNotSupportedException; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/ServerMessageType.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ServerMessageType.java similarity index 93% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/ServerMessageType.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/ServerMessageType.java index 2b14284f..6beb004b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/ServerMessageType.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ServerMessageType.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets; +package com.edgedb.driver.binary.protocol; import com.edgedb.driver.binary.BinaryEnum; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java new file mode 100644 index 00000000..c718aeac --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java @@ -0,0 +1,24 @@ +package com.edgedb.driver.binary.protocol; + +import com.edgedb.driver.binary.protocol.v1.descriptors.TypeDescriptor; + +import java.util.UUID; + +public class TypeDescriptorInfo> { + public final TypeDescriptor descriptor; + public final T type; + + public TypeDescriptorInfo(TypeDescriptor descriptor, T type) { + this.descriptor = descriptor; + this.type = type; + } + + public UUID getId() { + return descriptor.getId(); + } + + @SuppressWarnings("unchecked") + public U as(Class ignored) { + return (U)descriptor; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/Annotation.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/Annotation.java similarity index 95% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/Annotation.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/Annotation.java index fcbb9d35..729633d3 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/Annotation.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/Annotation.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/AuthStatus.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/AuthStatus.java similarity index 90% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/AuthStatus.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/AuthStatus.java index d01edadb..1ba2c9ee 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/AuthStatus.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/AuthStatus.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.BinaryEnum; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/Cardinality.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/Cardinality.java similarity index 90% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/Cardinality.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/Cardinality.java index 498c6d79..276a63e7 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/Cardinality.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/Cardinality.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.BinaryEnum; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/CompilationFlags.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/CompilationFlags.java similarity index 90% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/CompilationFlags.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/CompilationFlags.java index 1baad721..4e28f422 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/CompilationFlags.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/CompilationFlags.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.BinaryEnum; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/ConnectionParam.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ConnectionParam.java similarity index 94% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/ConnectionParam.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ConnectionParam.java index 4c504e37..b803cc44 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/ConnectionParam.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ConnectionParam.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.SerializableData; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/DumpObjectDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/DumpObjectDescriptor.java similarity index 93% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/DumpObjectDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/DumpObjectDescriptor.java index 40f8b7c0..8d41f74b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/DumpObjectDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/DumpObjectDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.PacketReader; import io.netty.buffer.ByteBuf; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/DumpTypeInfo.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/DumpTypeInfo.java similarity index 89% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/DumpTypeInfo.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/DumpTypeInfo.java index 228b3fc3..70c9b518 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/DumpTypeInfo.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/DumpTypeInfo.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/IOFormat.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/IOFormat.java similarity index 89% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/IOFormat.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/IOFormat.java index fe2c3e3e..8ce7fd5d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/IOFormat.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/IOFormat.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.BinaryEnum; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/KeyValue.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/KeyValue.java similarity index 95% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/KeyValue.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/KeyValue.java index 1027f4a0..34f306fa 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/KeyValue.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/KeyValue.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ProtocolError.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ProtocolError.java new file mode 100644 index 00000000..217eeda3 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ProtocolError.java @@ -0,0 +1,15 @@ +package com.edgedb.driver.binary.protocol.common; + +import com.edgedb.driver.ErrorCode; +import com.edgedb.driver.ErrorSeverity; +import org.joou.UShort; + +import java.util.Optional; + +public interface ProtocolError { + ErrorSeverity getSeverity(); + ErrorCode getErrorCode(); + String getMessage(); + + Optional tryGetAttribute(short code); +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/ProtocolExtension.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ProtocolExtension.java similarity index 95% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/ProtocolExtension.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ProtocolExtension.java index dcb5517b..1a95b43c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/shared/ProtocolExtension.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/ProtocolExtension.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.packets.shared; +package com.edgedb.driver.binary.protocol.common; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java new file mode 100644 index 00000000..112c027d --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java @@ -0,0 +1,854 @@ +package com.edgedb.driver.binary.protocol.v1; + +import com.edgedb.driver.Capabilities; +import com.edgedb.driver.ErrorCode; +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.builders.CodecBuilder; +import com.edgedb.driver.binary.codecs.*; +import com.edgedb.driver.binary.codecs.scalars.TextCodec; +import com.edgedb.driver.binary.duplexers.Duplexer; +import com.edgedb.driver.binary.protocol.*; +import com.edgedb.driver.binary.protocol.common.*; +import com.edgedb.driver.binary.protocol.v1.descriptors.*; +import com.edgedb.driver.binary.protocol.v1.receivables.*; +import com.edgedb.driver.binary.protocol.v1.sendables.*; +import com.edgedb.driver.clients.EdgeDBBinaryClient; +import com.edgedb.driver.datatypes.Range; +import com.edgedb.driver.exceptions.*; +import com.edgedb.driver.util.BinaryProtocolUtils; +import com.edgedb.driver.util.Scram; +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.naming.OperationNotSupportedException; +import java.lang.reflect.Array; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; + +import static com.edgedb.driver.util.ComposableUtil.exceptionallyCompose; +import static org.joou.Unsigned.ushort; + +public class V1ProtocolProvider implements ProtocolProvider { + private static final Logger logger = LoggerFactory.getLogger(V1ProtocolProvider.class); + private static final Map> DESERIALIZER_MAP; + private static final Map> TYPE_DESCRIPTOR_MAP; + private static final int MAX_PARSE_ATTEMPTS = 2; + + private static final Map EMPTY_SERVER_CONFIG = Collections.emptyMap(); + + static { + DESERIALIZER_MAP = new HashMap<>(){{ + put(ServerMessageType.AUTHENTICATION, AuthenticationStatus::new); + put(ServerMessageType.COMMAND_COMPLETE, CommandComplete::new); + put(ServerMessageType.COMMAND_DATA_DESCRIPTION, CommandDataDescription::new); + put(ServerMessageType.DATA, Data::new); + put(ServerMessageType.DUMP_BLOCK, DumpBlock::new); + put(ServerMessageType.DUMP_HEADER, DumpHeader::new); + put(ServerMessageType.ERROR_RESPONSE, ErrorResponse::new); + put(ServerMessageType.LOG_MESSAGE, LogMessage::new); + put(ServerMessageType.PARAMETER_STATUS, ParameterStatus::new); + put(ServerMessageType.READY_FOR_COMMAND, ReadyForCommand::new); + put(ServerMessageType.RESTORE_READY, RestoreReady::new); + put(ServerMessageType.SERVER_HANDSHAKE, ServerHandshake::new); + put(ServerMessageType.SERVER_KEY_DATA, ServerKeyData::new); + put(ServerMessageType.STATE_DATA_DESCRIPTION, StateDataDescription::new); + }}; + + TYPE_DESCRIPTOR_MAP = new HashMap<>(){{ + put(DescriptorType.ARRAY_TYPE_DESCRIPTOR, ArrayTypeDescriptor::new); + put(DescriptorType.BASE_SCALAR_TYPE_DESCRIPTOR, BaseScalarTypeDescriptor::new); + put(DescriptorType.ENUMERATION_TYPE_DESCRIPTOR, EnumerationTypeDescriptor::new); + put(DescriptorType.NAMED_TUPLE_DESCRIPTOR, NamedTupleTypeDescriptor::new); + put(DescriptorType.OBJECT_SHAPE_DESCRIPTOR, ObjectShapeDescriptor::new); + put(DescriptorType.SCALAR_TYPE_DESCRIPTOR, ScalarTypeDescriptor::new); + put(DescriptorType.SCALAR_TYPE_NAME_ANNOTATION, ScalarTypeNameAnnotation::new); + put(DescriptorType.SET_DESCRIPTOR, SetTypeDescriptor::new); + put(DescriptorType.TUPLE_TYPE_DESCRIPTOR, TupleTypeDescriptor::new); + put(DescriptorType.INPUT_SHAPE_DESCRIPTOR, InputShapeDescriptor::new); + put(DescriptorType.RANGE_TYPE_DESCRIPTOR, RangeTypeDescriptor::new); + }}; + } + + private ProtocolPhase phase; + private final EdgeDBBinaryClient client; + private @Nullable Map rawServerConfig; + + public V1ProtocolProvider(EdgeDBBinaryClient client) { + this.client = client; + + this.phase = ProtocolPhase.CONNECTION; + } + + @Override + public ProtocolVersion getVersion() { + return ProtocolVersion.of(1, 0); + } + + @Override + public ProtocolPhase getPhase() { + return this.phase; + } + + @Override + public Map getServerConfig() { + return rawServerConfig == null ? EMPTY_SERVER_CONFIG : rawServerConfig; + } + + @Override + public Receivable readPacket(ServerMessageType type, int length, PacketReader reader) throws UnexpectedMessageException { + if(!DESERIALIZER_MAP.containsKey(type)) { + logger.error("Unknown packet type {}", type); + reader.skip(length); + throw new UnexpectedMessageException("Unsupported message type " + type); + } + + return DESERIALIZER_MAP.get(type).apply(reader); + } + + @Override + public TypeDescriptorInfo readDescriptor(PacketReader reader) throws UnexpectedMessageException { + var type = reader.readEnum(DescriptorType.class, Byte.TYPE); + var id = reader.readUUID(); + + if(!TYPE_DESCRIPTOR_MAP.containsKey(type)) { + logger.error("Unknown type descriptor {}", type); + throw new UnexpectedMessageException("Unsupported descriptor type " + type); + } + + return new TypeDescriptorInfo<>(TYPE_DESCRIPTOR_MAP.get(type).apply(id, reader), type); + } + + @SuppressWarnings("unchecked") + @Override + public > @Nullable Codec buildCodec( + TypeDescriptorInfo descriptor, Function> getRelativeCodec, + Function getRelativeDescriptor + ) throws MissingCodecException { + if(!(descriptor.type instanceof DescriptorType)) { + throw new IllegalArgumentException("Expected v1 descriptor type, got " + descriptor.type.getClass().getName()); + } + + switch ((DescriptorType)descriptor.type) { + case ARRAY_TYPE_DESCRIPTOR: + var arrayType = descriptor.as(ArrayTypeDescriptor.class); + + return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> + new CompilableCodec( + getRelativeCodec.apply(arrayType.typePosition.intValue()), + ArrayCodec::new, + t -> Array.newInstance(t,0).getClass() + ) + ); + case SCALAR_TYPE_DESCRIPTOR: + case BASE_SCALAR_TYPE_DESCRIPTOR: + // should be resolved by the above case, getting here is an error + throw new MissingCodecException(String.format("Could not find the scalar type %s", descriptor.getId().toString())); + case ENUMERATION_TYPE_DESCRIPTOR: + return CodecBuilder.getOrCreateCodec(descriptor.getId(), TextCodec::new); + case INPUT_SHAPE_DESCRIPTOR: + var inputShape = descriptor.as(InputShapeDescriptor.class); + var inputShapeCodecs = new Codec[inputShape.shapes.length]; + var inputShapeNames = new String[inputShape.shapes.length]; + + for (int i = 0; i != inputShape.shapes.length; i++) { + inputShapeCodecs[i] = getRelativeCodec.apply(inputShape.shapes[i].typePosition.intValue()); + inputShapeNames[i] = inputShape.shapes[i].name; + } + + return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> new SparseObjectCodec(inputShapeCodecs, inputShapeNames)); + case TUPLE_TYPE_DESCRIPTOR: + var tupleType = descriptor.as(TupleTypeDescriptor.class); + var innerCodecs = new Codec[tupleType.elementTypeDescriptorPositions.length]; + + for(int i = 0; i != innerCodecs.length; i++) { + innerCodecs[i] = getRelativeCodec.apply(tupleType.elementTypeDescriptorPositions[i].intValue()); + } + + return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> new TupleCodec(innerCodecs)); + case NAMED_TUPLE_DESCRIPTOR: + var tupleShape = descriptor.as(NamedTupleTypeDescriptor.class); + return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, tupleShape.elements)); + case OBJECT_SHAPE_DESCRIPTOR: + var objectShape = descriptor.as(ObjectShapeDescriptor.class); + return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, objectShape.shapes)); + case RANGE_TYPE_DESCRIPTOR: + var rangeType = descriptor.as(RangeTypeDescriptor.class); + + return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> + new CompilableCodec( + getRelativeCodec.apply(rangeType.typePosition.intValue()), + RangeCodec::new, + t -> Range.empty(t).getClass() + ) + ); + case SCALAR_TYPE_NAME_ANNOTATION: + return null; + case SET_DESCRIPTOR: + var setTypes = descriptor.as(SetTypeDescriptor.class); + + return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> + new CompilableCodec( + getRelativeCodec.apply(setTypes.typePosition.intValue()), + SetCodec::new, + t -> Array.newInstance(t, 0).getClass() + ) + ); + default: + throw new MissingCodecException(String.format("Could not find a type descriptor with the type %s", descriptor.getId().toString())); + } + } + + public static class ProtocolState { + public int attempts; + public ByteBuf stateBuffer; + + public EnumSet capabilities; + public Cardinality cardinality; + + public boolean stateUpdated; + + public CodecBuilder.QueryCodecs codecs; + + public boolean isComplete; + + public List data; + + public ProtocolState(QueryParameters args, ByteBuf stateBuffer) { + this.stateBuffer = stateBuffer; + this.capabilities = args.capabilities; + this.cardinality = args.cardinality; + } + + public ProtocolState(QueryParameters args, ByteBuf stateBuffer, List data) { + this(args, stateBuffer); + this.data = data; + } + } + + @Override + public CompletionStage parseQuery(QueryParameters queryParameters) { + var cacheKey = queryParameters.getCacheKey(); + + var cachedCodecs = CodecBuilder.getCachedCodecs(cacheKey); + + ByteBuf stateBuffer; + + try { + stateBuffer = client.serializeState(); + } catch (OperationNotSupportedException | EdgeDBException e) { + return CompletableFuture.failedFuture(e); + } + + if(cachedCodecs == null) { + ProtocolState parseState = new ProtocolState(queryParameters, stateBuffer); + + return runWithAttempts( + queryParameters, + a -> parse0(a, parseState), + ignored -> parseState.isComplete, + () -> parseState.attempts++ + ).thenApply(v -> + new ParseResult( + parseState.codecs.inputCodec, parseState.codecs.outputCodec, parseState.codecs.inputCodecId, + parseState.codecs.outputCodecId, parseState.stateBuffer, parseState.capabilities, + parseState.cardinality + ) + ); + } + + return CompletableFuture.completedFuture( + new ParseResult( + cachedCodecs.inputCodec, + cachedCodecs.outputCodec, + cachedCodecs.inputCodecId, + cachedCodecs.outputCodecId, + stateBuffer, + queryParameters.capabilities, + queryParameters.cardinality + ) + ); + } + + private CompletionStage parse0(@NotNull QueryParameters args, ProtocolState state) { + if(state.attempts > MAX_PARSE_ATTEMPTS) { + logger.debug("Parse attempts exceeded {}", MAX_PARSE_ATTEMPTS); + return CompletableFuture.failedFuture( + new EdgeDBException("Failed to parse query after " + state.attempts + " attempts") + ); + } + + var parseCardinality = state.cardinality; + var parseCapabilities = state.capabilities; + var stateBuffer = state.stateBuffer; + + logger.debug("Starting to parse... attempt {}/{}", state.attempts + 1, MAX_PARSE_ATTEMPTS); + + return client.getDuplexer().duplexAndSync(new Parse( + parseCapabilities, + getCompilationFlags(args), + args.format, + parseCardinality, + args.query, + client.getConfig().getImplicitLimit(), + client.getStateDescriptorId(), + stateBuffer + ), (result) -> { + logger.trace("parse duplex result: {}", result.packet.getMessageType()); + switch (result.packet.getMessageType()) { + case ERROR_RESPONSE: + var err = result.packet.as(ErrorResponse.class); + logger.debug("handling error: {}", err.errorCode); + handleCommandError(args, state, result, err); + return CompletableFuture.completedFuture(null); + case COMMAND_DATA_DESCRIPTION: + var commandDescriptor = result.packet.as(CommandDataDescription.class); + + logger.debug("parsing command data description"); + + if(!Objects.equals(args.capabilities, commandDescriptor.capabilities)) { + logger.debug( + "actual capabilities differ from the provided ones: provided: {}. actual: {}", + args.capabilities, + commandDescriptor.capabilities + ); + + state.capabilities = commandDescriptor.capabilities; + } + + if(args.cardinality != commandDescriptor.cardinality) { + logger.debug( + "actual cardinality differs from the provided one: provided: {}. actual: {}", + args.cardinality, + commandDescriptor.cardinality + ); + + state.cardinality = commandDescriptor.cardinality; + } + + state.codecs = new CodecBuilder.QueryCodecs( + commandDescriptor.inputTypeDescriptorId, + CodecBuilder.buildCodec( + commandDescriptor.inputTypeDescriptorId, + commandDescriptor.inputTypeDescriptorBuffer + ), + commandDescriptor.outputTypeDescriptorId, + CodecBuilder.buildCodec( + commandDescriptor.outputTypeDescriptorId, + commandDescriptor.outputTypeDescriptorBuffer + ) + ); + + logger.debug( + "updating codec query cache key {} with I:{} O:{}", + args.getCacheKey(), + commandDescriptor.inputTypeDescriptorId, + commandDescriptor.outputTypeDescriptorId + ); + + CodecBuilder.updateCachedCodecs( + args.getCacheKey(), + commandDescriptor.inputTypeDescriptorId, + commandDescriptor.outputTypeDescriptorId + ); + break; + case STATE_DATA_DESCRIPTION: + updateStateCodec(state, result); + break; + case READY_FOR_COMMAND: + var ready = result.packet.as(ReadyForCommand.class); + client.setTransactionState(ready.transactionState); + result.finishDuplexing(); + } + + return CompletableFuture.completedFuture(null); + }); + } + + @Override + public CompletionStage executeQuery(QueryParameters queryParameters, ParseResult parseResult) { + var data = new ArrayList(); + var state = new ProtocolState(queryParameters, parseResult.stateData, data); + + return runWithAttempts( + queryParameters, + p -> execute0(p, parseResult, state), + p -> state.isComplete, + () -> state.attempts++ + ).thenApply(v -> + new ExecuteResult( + parseResult.outCodec, + data + ) + ); + } + + private CompletionStage execute0(QueryParameters queryParameters, ParseResult parseResult, ProtocolState state) { + if(state.attempts > 2) { + return CompletableFuture.failedFuture( + new EdgeDBException("Failed to parse query after " + state.attempts + " attempts") + ); + } + + if(!(parseResult.inCodec instanceof ArgumentCodec)) { + return CompletableFuture.failedFuture( + new MissingCodecException(String.format( + "Cannot encode arguments, %s is not a valid argument codec", + parseResult.inCodec.toString()) + ) + ); + } + + try { + return client.getDuplexer().duplexAndSync(new Execute( + parseResult.capabilities, + getCompilationFlags(queryParameters), + client.getConfig().getImplicitLimit(), + queryParameters.format, + parseResult.cardinality, + queryParameters.query, + client.getStateDescriptorId(), + parseResult.stateData, + parseResult.inCodecId, + parseResult.outCodecId, + ArgumentCodec.serializeToBuffer( + (ArgumentCodec) parseResult.inCodec, + queryParameters.arguments, + client.getCodecContext() + ) + ), (result) -> { + switch (result.packet.getMessageType()) { + case DATA: + var data = result.packet.as(Data.class); + assert data.payloadBuffer != null; + // retain the data buffer once, so it's available for the + // consumer of data, since after this duplex step, `Data` and + // its children (buffers) are freed. + data.payloadBuffer.retain(); + state.data.add(data.payloadBuffer); + break; + case STATE_DATA_DESCRIPTION: + updateStateCodec(state, result); + break; + case ERROR_RESPONSE: + var err = result.packet.as(ErrorResponse.class); + handleCommandError(queryParameters, state, result, err); + break; + case READY_FOR_COMMAND: + var ready = result.packet.as(ReadyForCommand.class); + client.setTransactionState(ready.transactionState); + state.isComplete = true; + result.finishDuplexing(); + break; + } + + return CompletableFuture.completedFuture(null); + }); + } catch (OperationNotSupportedException | EdgeDBException e) { + return CompletableFuture.failedFuture(e); + } + } + + private @NotNull EnumSet getCompilationFlags(QueryParameters args) { + var flags = EnumSet.of(CompilationFlags.NONE); + + if(client.getConfig().getImplicitTypeIds()) { + flags.add(CompilationFlags.IMPLICIT_TYPE_IDS); + } + + if(args.implicitTypeNames) { + flags.add(CompilationFlags.IMPLICIT_TYPE_NAMES); + } + + if(!client.getConfig().getExplicitObjectIds()) { + flags.add(CompilationFlags.EXPLICIT_OBJECT_IDS); + } + + return flags; + } + + private void handleCommandError(@NotNull QueryParameters queryParameters, @NotNull V1ProtocolProvider.ProtocolState args, Duplexer.@NotNull DuplexResult result, @NotNull ErrorResponse err) { + if(err.errorCode == ErrorCode.STATE_MISMATCH_ERROR) { + logger.debug("Has updated state?: {}", args.stateUpdated); + // should have new state + if(!args.stateUpdated) { + result.finishExceptionally( + "Failed to properly encode state data, this is a bug", + EdgeDBException::new + ); + } + } + else { + result.finishExceptionally(err, queryParameters.query, ErrorResponse::toException); + } + } + + private void updateStateCodec(ProtocolState state, Duplexer.@NotNull DuplexResult result) { + var stateDescriptor = result.packet.as(StateDataDescription.class); + var codec = CodecBuilder.getCodec(stateDescriptor.typeDescriptorId, Map.class); + + if(codec == null) { + try { + codec = CodecBuilder.buildCodec( + stateDescriptor.typeDescriptorId, + stateDescriptor.typeDescriptorBuffer, + Map.class + ); + } catch (EdgeDBException | OperationNotSupportedException e) { + result.finishExceptionally("Failed to parse state codec", e, EdgeDBException::new); + } + } + + client.setStateCodec(codec); + client.setStateDescriptorId(stateDescriptor.typeDescriptorId); + state.stateUpdated = true; + + try { + state.stateBuffer = client.serializeState(); + } catch (OperationNotSupportedException | EdgeDBException e) { + result.finishExceptionally("Failed to serialize state", e, EdgeDBException::new); + } + } + + private CompletionStage runWithAttempts( + QueryParameters args, + @NotNull Function> delegate, + @NotNull Predicate completedPredicate, + @NotNull Runnable incrementer + ) { + return delegate.apply(args) + .thenCompose((v) -> { + if(!completedPredicate.test(args)) { + incrementer.run(); + return runWithAttempts(args, delegate, completedPredicate, incrementer); + } + + return CompletableFuture.completedFuture(null); + }); + } + + @Override + public CompletionStage sendSyncMessage() { + if(!client.getDuplexer().isConnected()) { + return client.reconnect() + .thenCompose(v -> sendSyncMessage0(true)); + } + + return sendSyncMessage0(false); + } + + private CompletionStage sendSyncMessage0(boolean isRetry) { + return exceptionallyCompose(sendSyncMessage1(), e -> { + if(!isRetry) { + return sendSyncMessage0(true); + } + + return CompletableFuture.failedFuture(new EdgeDBException("Failed to send sync message after 2 attempts")); + }); + } + + private CompletionStage sendSyncMessage1() { + return client.getDuplexer() + .duplexSingle(sync()) + .thenAccept(r -> { + if(r == null) { + return; + } + + if(r instanceof ErrorResponse) { + throw new CompletionException(((ErrorResponse)r).toException()); + } + + if(!(r instanceof ReadyForCommand)) { + throw new CompletionException( + new UnexpectedMessageException( + ServerMessageType.READY_FOR_COMMAND, + r.getMessageType() + ) + ); + } + + client.setTransactionState(((ReadyForCommand)r).transactionState); + + }); + } + + @Override + public CompletionStage processMessage(Receivable packet) { + logger.debug("Processing packet {}", packet.getMessageType()); + + try { + switch (packet.getMessageType()) { + case SERVER_HANDSHAKE: + var handshake = (ServerHandshake)packet; + + if(!getVersion().equals(handshake.majorVersion, handshake.minorVersion)) { + var negotiated = client.tryNegotiateProtocol(handshake.majorVersion, handshake.minorVersion); + + if(!negotiated && getVersion().major != handshake.majorVersion.intValue()) { + // major mismatch + + logger.error( + "The server requested protocol version {}.{} but the currently installed client only " + + "supports {}. Please switch to a different client version that supports the " + + "requested protocol.", + handshake.majorVersion, handshake.majorVersion, + getVersion() + ); + + return client.disconnect(); + } else if (!negotiated) { + // minor mismatch + logger.warn( + "The server requested protocol version {}.{} but the currently installed client only " + + "supports {}. Functionality may be limited and bugs may arise, please switch to " + + "a different client version that supports the requested protocol.", + handshake.majorVersion, handshake.majorVersion, + getVersion() + ); + } + + if(negotiated) { + // this providers lifecycle is complete. + return CompletableFuture.completedFuture(null); + } + } + break; + case ERROR_RESPONSE: + var error = (ErrorResponse)packet; + + logger.error("{} - {}: {}", error.severity, error.errorCode, error.message); + + var exc = error.toException(); + + phase = ProtocolPhase.ERRORED; + client.cancelReadyState(exc); + return CompletableFuture.failedFuture(exc); + case AUTHENTICATION: + var auth = (AuthenticationStatus)packet; + if(auth.authStatus == AuthStatus.AUTHENTICATION_REQUIRED_SASL_MESSAGE) { + return startSASLAuthentication(auth); + } else if (auth.authStatus != AuthStatus.AUTHENTICATION_OK) { + throw new UnexpectedMessageException( + "Expected AuthenticationRequiredSASLMessage, got " + auth.authStatus + ); + } + break; + case SERVER_KEY_DATA: + // eventually used + byte[] serverKey = new byte[32]; + ((ServerKeyData)packet).keyData.readBytes(serverKey); + break; + case STATE_DATA_DESCRIPTION: + var stateDescriptor = (StateDataDescription)packet; + + var codec = CodecBuilder.getCodec(stateDescriptor.typeDescriptorId, Map.class); + + if(codec == null) { + assert stateDescriptor.typeDescriptorBuffer != null; + + var reader = new PacketReader(stateDescriptor.typeDescriptorBuffer); + codec = CodecBuilder.buildCodec(stateDescriptor.typeDescriptorId, reader, Map.class); + } + + client.setStateDescriptorId(stateDescriptor.typeDescriptorId); + client.setStateCodec(codec); + break; + case PARAMETER_STATUS: + parseServerSettings((ParameterStatus) packet); + break; + case LOG_MESSAGE: + var msg = (LogMessage)packet; + var formatted = msg.format(); + switch (msg.severity) { + case INFO: + case NOTICE: + logger.info(formatted); + break; + case DEBUG: + logger.debug(formatted); + break; + case WARNING: + logger.warn(formatted); + break; + } + break; + } + } + catch (Exception x) { + logger.debug("Processing failed", x); + return CompletableFuture.failedFuture(x); + } + + logger.debug("Processing pass-through to completed result"); + + return CompletableFuture.completedFuture(null); + } + + private void parseServerSettings(@NotNull ParameterStatus status) throws EdgeDBException, OperationNotSupportedException { + switch (status.name) { + case "suggested_pool_concurrency": + assert status.value != null; + + var buffer = new byte[status.value.readableBytes()]; + status.value.readBytes(buffer); + var str = new String(buffer, StandardCharsets.UTF_8); + + try { + client.setSuggestedPoolConcurrency(Long.parseLong(str)); + } catch (NumberFormatException x) { + logger.error("suggested_pool_concurrency wasn't in a numeric format", x); + } + break; + case "system_config": + assert status.value != null; + + var reader = new PacketReader(status.value); + var descriptorLength = reader.readInt32() - 16; + var descriptorId = reader.readUUID(); + + var codec = CodecBuilder.getCodec(descriptorId, Map.class); + + if(codec == null) { + var descriptorReader = new PacketReader(reader.readBytes(descriptorLength)); + codec = CodecBuilder.buildCodec(descriptorId, descriptorReader, Map.class); + } + + reader.skip(BinaryProtocolUtils.INT_SIZE); // discard length + + //noinspection unchecked + this.rawServerConfig = codec.deserialize(reader, client.getCodecContext()); + break; + } + } + + private CompletionStage startSASLAuthentication(@NotNull AuthenticationStatus authStatus) throws ScramException { + this.phase = ProtocolPhase.AUTH; + + final var scram = new Scram(); + + assert authStatus.authenticationMethods != null; + + var method = authStatus.authenticationMethods[0]; + + assert method != null; + + if(!method.equals("SCRAM-SHA-256")) { + throw new ScramException("The only supported method is SCRAM-SHA-256, but the server wants " + method); + } + + var connection = client.getConnectionArguments(); + var initialMessage = scram.buildInitialMessagePacket(connection.getUsername(), method); + + AtomicReference signature = new AtomicReference<>(new byte[0]); + + try{ + return client.getDuplexer().duplex(initialMessage, (state) -> { + logger.debug("Authentication duplex: M:{}", state.packet.getMessageType()); + try { + switch (state.packet.getMessageType()) { + case AUTHENTICATION: + var auth = (AuthenticationStatus)state.packet; + + logger.debug("Processing auth part: {}", auth.authStatus); + + switch (auth.authStatus) { + case AUTHENTICATION_SASL_CONTINUE: + var result = scram.buildFinalMessage(auth, connection.getPassword()); + signature.set(result.signature); + return client.getDuplexer().send(result.buildPacket()); + case AUTHENTICATION_SASL_FINAL: + var key = Scram.parseServerFinalMessage(auth); + + if(!Arrays.equals(signature.get(), key)) { + logger.error( + "The SCRAM signature didn't match. ours: {}, servers: {}.", + signature.get(), + key + ); + throw new InvalidSignatureException(); + } + break; + case AUTHENTICATION_OK: + logger.debug("Completing auth duplex"); + state.finishDuplexing(); + this.phase = ProtocolPhase.COMMAND; + break; + default: + throw new UnexpectedMessageException( + "Expected continue or final but got " + auth.authStatus + ); + } + break; + case ERROR_RESPONSE: + throw ((ErrorResponse)state.packet).toException(); + default: + logger.error( + "Unexpected message. expected: {} actual: {}", + ServerMessageType.AUTHENTICATION, + state.packet.getMessageType() + ); + throw new CompletionException( + new UnexpectedMessageException( + ServerMessageType.AUTHENTICATION, + state.packet.getMessageType() + ) + ); + } + } // TODO: should reconnect & should retry exceptions + catch (Exception err) { + this.phase = ProtocolPhase.ERRORED; + state.finishExceptionally(err); + return CompletableFuture.failedFuture(err); + } + + return CompletableFuture.completedFuture(null); + }); + } + catch (Throwable x) { + return CompletableFuture.failedFuture(x); + } + } + + + @Override + public Sendable handshake() { + var connection = client.getConnectionArguments(); + + var connectionParams = connection.getSecretKey() != null + ? new ConnectionParam[] { + new ConnectionParam("user", connection.getUsername()), + new ConnectionParam("database", connection.getDatabase()), + new ConnectionParam("secret_key", connection.getSecretKey()) + } : new ConnectionParam[] { + new ConnectionParam("user", connection.getUsername()), + new ConnectionParam("database", connection.getDatabase()) + }; + + return new ClientHandshake( + ushort(getVersion().major), + ushort(getVersion().minor), + connectionParams, + new ProtocolExtension[0] + ); + } + + @Override + public Sendable terminate() { + return Terminate.INSTANCE; + } + + @Override + public Sendable sync() { + return Sync.INSTANCE; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ArrayTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ArrayTypeDescriptor.java similarity index 92% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ArrayTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ArrayTypeDescriptor.java index 00ba2b61..4a47b376 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ArrayTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ArrayTypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/BaseScalarTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/BaseScalarTypeDescriptor.java similarity index 85% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/BaseScalarTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/BaseScalarTypeDescriptor.java index 3f99e91e..67fdf1a5 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/BaseScalarTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/BaseScalarTypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/DescriptorType.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/DescriptorType.java similarity index 93% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/DescriptorType.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/DescriptorType.java index dc9d6eb5..2ded7c1d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/DescriptorType.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/DescriptorType.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.BinaryEnum; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/EnumerationTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/EnumerationTypeDescriptor.java similarity index 90% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/EnumerationTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/EnumerationTypeDescriptor.java index 885fc327..62e65039 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/EnumerationTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/EnumerationTypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/InputShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java similarity index 80% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/InputShapeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java index 78754acf..7428009b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/InputShapeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java @@ -1,6 +1,6 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; -import com.edgedb.driver.binary.descriptors.common.ShapeElement; +import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/NamedTupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java similarity index 81% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/NamedTupleTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java index 0a90792b..18595936 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/NamedTupleTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java @@ -1,7 +1,7 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.descriptors.common.TupleElement; +import com.edgedb.driver.binary.protocol.v1.descriptors.common.TupleElement; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ObjectShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java similarity index 80% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ObjectShapeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java index e41a95a1..8546a2e9 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ObjectShapeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java @@ -1,6 +1,6 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; -import com.edgedb.driver.binary.descriptors.common.ShapeElement; +import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/RangeTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/RangeTypeDescriptor.java similarity index 89% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/RangeTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/RangeTypeDescriptor.java index 49bebeec..db87d1dc 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/RangeTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/RangeTypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ScalarTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeDescriptor.java similarity index 90% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ScalarTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeDescriptor.java index e107fa29..b754556e 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ScalarTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ScalarTypeNameAnnotation.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeNameAnnotation.java similarity index 89% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ScalarTypeNameAnnotation.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeNameAnnotation.java index a85634a1..902d1240 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/ScalarTypeNameAnnotation.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeNameAnnotation.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/SetTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/SetTypeDescriptor.java similarity index 89% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/SetTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/SetTypeDescriptor.java index 18913bea..e7919f94 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/SetTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/SetTypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TupleTypeDescriptor.java similarity index 91% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TupleTypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TupleTypeDescriptor.java index 95b13b72..8a78c93d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TupleTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TupleTypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TypeAnnotationDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeAnnotationDescriptor.java similarity index 91% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TypeAnnotationDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeAnnotationDescriptor.java index 58f22efd..2dddc4ea 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TypeAnnotationDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeAnnotationDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeDescriptor.java similarity index 57% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeDescriptor.java index de179f5e..1c8c8460 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/TypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors; +package com.edgedb.driver.binary.protocol.v1.descriptors; import java.util.UUID; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/ShapeElement.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElement.java similarity index 84% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/ShapeElement.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElement.java index 72d2741e..e0c29a37 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/ShapeElement.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElement.java @@ -1,6 +1,6 @@ -package com.edgedb.driver.binary.descriptors.common; +package com.edgedb.driver.binary.protocol.v1.descriptors.common; -import com.edgedb.driver.binary.packets.shared.Cardinality; +import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; import org.joou.UInteger; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/ShapeElementFlags.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElementFlags.java similarity index 88% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/ShapeElementFlags.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElementFlags.java index d6d2abed..432548ba 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/ShapeElementFlags.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElementFlags.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors.common; +package com.edgedb.driver.binary.protocol.v1.descriptors.common; import com.edgedb.driver.binary.BinaryEnum; import org.joou.UInteger; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/TupleElement.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/TupleElement.java similarity index 84% rename from src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/TupleElement.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/TupleElement.java index 390314ed..c6d4c0df 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/descriptors/common/TupleElement.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/TupleElement.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.descriptors.common; +package com.edgedb.driver.binary.protocol.v1.descriptors.common; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/AuthenticationStatus.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/AuthenticationStatus.java similarity index 85% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/AuthenticationStatus.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/AuthenticationStatus.java index 7c1ecf03..c7e2aab3 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/AuthenticationStatus.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/AuthenticationStatus.java @@ -1,8 +1,9 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; -import com.edgedb.driver.binary.packets.shared.AuthStatus; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.common.AuthStatus; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.ServerMessageType; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/CommandComplete.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/CommandComplete.java similarity index 83% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/CommandComplete.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/CommandComplete.java index b9c0e62b..7e6b8258 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/CommandComplete.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/CommandComplete.java @@ -1,9 +1,10 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.Capabilities; -import com.edgedb.driver.binary.packets.shared.Annotation; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.common.Annotation; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.ServerMessageType; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/CommandDataDescription.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/CommandDataDescription.java similarity index 84% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/CommandDataDescription.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/CommandDataDescription.java index 9e7701ba..6b943612 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/CommandDataDescription.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/CommandDataDescription.java @@ -1,10 +1,11 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.Capabilities; -import com.edgedb.driver.binary.packets.shared.Annotation; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.common.Annotation; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; -import com.edgedb.driver.binary.packets.shared.Cardinality; +import com.edgedb.driver.binary.protocol.ServerMessageType; +import com.edgedb.driver.binary.protocol.common.Cardinality; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/Data.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/Data.java similarity index 82% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/Data.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/Data.java index 3b05b448..52a25854 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/Data.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/Data.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.ServerMessageType; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/DumpBlock.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/DumpBlock.java similarity index 69% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/DumpBlock.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/DumpBlock.java index 70333f26..0a031b7c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/DumpBlock.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/DumpBlock.java @@ -1,8 +1,9 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; -import com.edgedb.driver.binary.packets.shared.KeyValue; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.ServerMessageType; +import com.edgedb.driver.binary.protocol.common.KeyValue; import org.jetbrains.annotations.NotNull; public class DumpBlock implements Receivable { diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/DumpHeader.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/DumpHeader.java similarity index 76% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/DumpHeader.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/DumpHeader.java index 97578540..b8d62a43 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/DumpHeader.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/DumpHeader.java @@ -1,10 +1,11 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; -import com.edgedb.driver.binary.packets.shared.DumpObjectDescriptor; -import com.edgedb.driver.binary.packets.shared.DumpTypeInfo; -import com.edgedb.driver.binary.packets.shared.KeyValue; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.ServerMessageType; +import com.edgedb.driver.binary.protocol.common.DumpObjectDescriptor; +import com.edgedb.driver.binary.protocol.common.DumpTypeInfo; +import com.edgedb.driver.binary.protocol.common.KeyValue; import org.jetbrains.annotations.NotNull; import org.joou.UInteger; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ErrorResponse.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ErrorResponse.java similarity index 58% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ErrorResponse.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ErrorResponse.java index e65f03dd..0a0cce9c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ErrorResponse.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ErrorResponse.java @@ -1,28 +1,42 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.ErrorCode; import com.edgedb.driver.ErrorSeverity; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; -import com.edgedb.driver.binary.packets.shared.KeyValue; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.ServerMessageType; +import com.edgedb.driver.binary.protocol.common.KeyValue; +import com.edgedb.driver.binary.protocol.common.ProtocolError; import com.edgedb.driver.exceptions.EdgeDBErrorException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; -public class ErrorResponse implements Receivable { +public class ErrorResponse implements Receivable, ProtocolError { public final ErrorSeverity severity; public final ErrorCode errorCode; public final @NotNull String message; public final KeyValue @NotNull [] attributes; + public final Map attributesMap; + public ErrorResponse(@NotNull PacketReader reader) { severity = reader.readEnum(ErrorSeverity.class, Byte.TYPE); errorCode = reader.readEnum(ErrorCode.class, Integer.TYPE); message = reader.readString(); attributes = reader.readAttributes(); + + attributesMap = new HashMap<>() {{ + for (int i = 0; i != attributes.length; i++) { + put(attributes[i].code, attributes[i]); + } + }}; + } public @NotNull EdgeDBErrorException toException() { @@ -48,10 +62,36 @@ public ErrorResponse(@NotNull PacketReader reader) { @Override public void close() throws Exception { release(attributes); + attributesMap.clear(); + } @Override public @NotNull ServerMessageType getMessageType() { return ServerMessageType.ERROR_RESPONSE; } + + @Override + public ErrorSeverity getSeverity() { + return this.severity; + } + + @Override + public ErrorCode getErrorCode() { + return this.errorCode; + } + + @Override + public @NotNull String getMessage() { + return this.message; + } + + @Override + public Optional tryGetAttribute(short code) { + if(!attributesMap.containsKey(code)) { + return Optional.empty(); + } + + return Optional.of(attributesMap.get(code)); + } } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/LogMessage.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/LogMessage.java similarity index 79% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/LogMessage.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/LogMessage.java index 000fbdf7..2432ac8b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/LogMessage.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/LogMessage.java @@ -1,10 +1,11 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; -import com.edgedb.driver.binary.packets.shared.Annotation; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.common.Annotation; import com.edgedb.driver.ErrorCode; import com.edgedb.driver.LogSeverity; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.ServerMessageType; import org.jetbrains.annotations.NotNull; public class LogMessage implements Receivable { diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ParameterStatus.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ParameterStatus.java similarity index 80% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ParameterStatus.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ParameterStatus.java index e0aa5dbd..f30e9baf 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ParameterStatus.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ParameterStatus.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.ServerMessageType; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ReadyForCommand.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ReadyForCommand.java similarity index 72% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ReadyForCommand.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ReadyForCommand.java index 580971f9..36c86f57 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ReadyForCommand.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ReadyForCommand.java @@ -1,9 +1,10 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; -import com.edgedb.driver.binary.packets.shared.Annotation; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.common.Annotation; import com.edgedb.driver.TransactionState; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.ServerMessageType; import org.jetbrains.annotations.NotNull; public class ReadyForCommand implements Receivable { diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/RestoreReady.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/RestoreReady.java similarity index 69% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/RestoreReady.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/RestoreReady.java index 78c1eb77..847cfa55 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/RestoreReady.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/RestoreReady.java @@ -1,8 +1,9 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; -import com.edgedb.driver.binary.packets.shared.Annotation; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.common.Annotation; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.ServerMessageType; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ServerHandshake.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ServerHandshake.java similarity index 74% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ServerHandshake.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ServerHandshake.java index a99d32c3..1f19b85e 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ServerHandshake.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ServerHandshake.java @@ -1,8 +1,9 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; -import com.edgedb.driver.binary.packets.shared.ProtocolExtension; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.common.ProtocolExtension; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.ServerMessageType; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ServerKeyData.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ServerKeyData.java similarity index 78% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ServerKeyData.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ServerKeyData.java index 3c97c2cb..19e811ad 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/ServerKeyData.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/ServerKeyData.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.ServerMessageType; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/StateDataDescription.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/StateDataDescription.java similarity index 82% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/StateDataDescription.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/StateDataDescription.java index 275babb3..78df6e4d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/receivable/StateDataDescription.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/receivables/StateDataDescription.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.packets.receivable; +package com.edgedb.driver.binary.protocol.v1.receivables; import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.packets.ServerMessageType; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.ServerMessageType; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/AuthenticationSASLInitialResponse.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/AuthenticationSASLInitialResponse.java similarity index 84% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/AuthenticationSASLInitialResponse.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/AuthenticationSASLInitialResponse.java index 526192e1..6b58596e 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/AuthenticationSASLInitialResponse.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/AuthenticationSASLInitialResponse.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; import com.edgedb.driver.util.BinaryProtocolUtils; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/AuthenticationSASLResponse.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/AuthenticationSASLResponse.java similarity index 81% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/AuthenticationSASLResponse.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/AuthenticationSASLResponse.java index 3cbea2de..db4caf11 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/AuthenticationSASLResponse.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/AuthenticationSASLResponse.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; import com.edgedb.driver.util.BinaryProtocolUtils; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/ClientHandshake.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/ClientHandshake.java similarity index 83% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/ClientHandshake.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/ClientHandshake.java index e4802c8c..ea56f05d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/ClientHandshake.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/ClientHandshake.java @@ -1,9 +1,10 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.shared.ConnectionParam; -import com.edgedb.driver.binary.packets.shared.ProtocolExtension; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.binary.protocol.common.ConnectionParam; +import com.edgedb.driver.binary.protocol.common.ProtocolExtension; +import com.edgedb.driver.binary.protocol.ClientMessageType; import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Dump.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Dump.java similarity index 75% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Dump.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Dump.java index 498a1632..2acedd3a 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Dump.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Dump.java @@ -1,8 +1,9 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; -import com.edgedb.driver.binary.packets.shared.Annotation; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.binary.protocol.common.Annotation; import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Execute.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Execute.java similarity index 89% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Execute.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Execute.java index 8484f573..66f55c32 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Execute.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Execute.java @@ -1,11 +1,12 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.Capabilities; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; -import com.edgedb.driver.binary.packets.shared.Cardinality; -import com.edgedb.driver.binary.packets.shared.CompilationFlags; -import com.edgedb.driver.binary.packets.shared.IOFormat; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.CompilationFlags; +import com.edgedb.driver.binary.protocol.common.IOFormat; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Parse.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Parse.java similarity index 87% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Parse.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Parse.java index 0d30be37..9c1ae1cc 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Parse.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Parse.java @@ -1,11 +1,12 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.Capabilities; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.shared.Cardinality; -import com.edgedb.driver.binary.packets.shared.CompilationFlags; -import com.edgedb.driver.binary.packets.shared.IOFormat; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.CompilationFlags; +import com.edgedb.driver.binary.protocol.common.IOFormat; +import com.edgedb.driver.binary.protocol.ClientMessageType; import com.edgedb.driver.util.BinaryProtocolUtils; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Restore.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Restore.java similarity index 79% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Restore.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Restore.java index ae9cd301..b3f53d21 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Restore.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Restore.java @@ -1,15 +1,16 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; -import com.edgedb.driver.binary.packets.shared.KeyValue; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.binary.protocol.common.KeyValue; import com.edgedb.driver.util.BinaryProtocolUtils; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import javax.naming.OperationNotSupportedException; -public class Restore extends Sendable{ +public class Restore extends Sendable { private final KeyValue[] attributes; private final short jobs; private final ByteBuf headerData; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/RestoreBlock.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/RestoreBlock.java similarity index 81% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/RestoreBlock.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/RestoreBlock.java index 080f0250..7df611f5 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/RestoreBlock.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/RestoreBlock.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; import com.edgedb.driver.util.BinaryProtocolUtils; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/RestoreEOF.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/RestoreEOF.java similarity index 57% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/RestoreEOF.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/RestoreEOF.java index 16eb977e..e5350ff4 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/RestoreEOF.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/RestoreEOF.java @@ -1,9 +1,10 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; -public class RestoreEOF extends Sendable{ +public class RestoreEOF extends Sendable { public RestoreEOF() { super(ClientMessageType.RESTORE_EOF); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Sync.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Sync.java similarity index 57% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Sync.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Sync.java index 2cacda21..91a135f3 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Sync.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Sync.java @@ -1,9 +1,12 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; public class Sync extends Sendable { + public static final Sendable INSTANCE = new Sync(); + public Sync() { super(ClientMessageType.SYNC); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Terminate.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Terminate.java similarity index 58% rename from src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Terminate.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Terminate.java index 8221e395..7f9e714b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/packets/sendables/Terminate.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/sendables/Terminate.java @@ -1,9 +1,12 @@ -package com.edgedb.driver.binary.packets.sendables; +package com.edgedb.driver.binary.protocol.v1.sendables; import com.edgedb.driver.binary.PacketWriter; -import com.edgedb.driver.binary.packets.ClientMessageType; +import com.edgedb.driver.binary.protocol.ClientMessageType; +import com.edgedb.driver.binary.protocol.Sendable; public class Terminate extends Sendable { + public static final Sendable INSTANCE = new Terminate(); + public Terminate() { super(ClientMessageType.TERMINATE); } diff --git a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java index 8fff9ae1..2146c8f0 100644 --- a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java +++ b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java @@ -1,24 +1,20 @@ package com.edgedb.driver.clients; import com.edgedb.driver.*; -import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.builders.CodecBuilder; import com.edgedb.driver.binary.builders.ObjectBuilder; import com.edgedb.driver.binary.builders.types.TypeBuilder; -import com.edgedb.driver.binary.codecs.ArgumentCodec; import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.duplexers.Duplexer; -import com.edgedb.driver.binary.packets.ServerMessageType; -import com.edgedb.driver.binary.packets.receivable.*; -import com.edgedb.driver.binary.packets.sendables.ClientHandshake; -import com.edgedb.driver.binary.packets.sendables.Execute; -import com.edgedb.driver.binary.packets.sendables.Parse; -import com.edgedb.driver.binary.packets.shared.*; +import com.edgedb.driver.binary.protocol.*; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.IOFormat; import com.edgedb.driver.datatypes.Json; -import com.edgedb.driver.exceptions.*; -import com.edgedb.driver.util.BinaryProtocolUtils; -import com.edgedb.driver.util.Scram; +import com.edgedb.driver.exceptions.ConnectionFailedException; +import com.edgedb.driver.exceptions.EdgeDBErrorException; +import com.edgedb.driver.exceptions.EdgeDBException; +import com.edgedb.driver.exceptions.ResultCardinalityMismatchException; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,35 +23,24 @@ import org.slf4j.LoggerFactory; import javax.naming.OperationNotSupportedException; -import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.function.Predicate; -import static com.edgedb.driver.util.ComposableUtil.composeWith; import static com.edgedb.driver.util.ComposableUtil.exceptionallyCompose; -import static org.joou.Unsigned.ushort; public abstract class EdgeDBBinaryClient extends BaseEdgeDBClient { private static final Logger logger = LoggerFactory.getLogger(EdgeDBBinaryClient.class); - - private static final UShort PROTOCOL_MAJOR_VERSION = ushort(1); - private static final UShort PROTOCOL_MINOR_VERSION = ushort(0); - - private static final int MAX_PARSE_ATTEMPTS = 2; - - public @Nullable Long suggestedPoolConcurrency; - public @Nullable Map rawServerConfig; - @SuppressWarnings("rawtypes") private @Nullable Codec stateCodec; private UUID stateDescriptorId; + private @Nullable Long suggestedPoolConcurrency; + private ProtocolProvider protocolProvider; private short connectionAttempts; - private boolean isIdle; private final @NotNull Semaphore connectionSemaphore; private final @NotNull Semaphore querySemaphore; private final @NotNull CompletableFuture readyPromise; @@ -69,234 +54,43 @@ public EdgeDBBinaryClient(EdgeDBConnection connection, EdgeDBClientConfig config this.stateDescriptorId = CodecBuilder.INVALID_CODEC_ID; } - protected abstract Duplexer getDuplexer(); + public abstract Duplexer getDuplexer(); + + public ProtocolProvider getProtocolProvider() { + return this.protocolProvider; + } @Override public @NotNull Optional getSuggestedPoolConcurrency() { return Optional.ofNullable(this.suggestedPoolConcurrency); } - public @NotNull CodecContext getCodecContext() { - return this.codecContext; - } - - public boolean getIsIdle() { - return isIdle; - } - - protected void setIsIdle(boolean value) { - isIdle = value; - } - - private CompletionStage parse(@NotNull ExecutionArguments args) { - return runWithAttempts( - args, - this::parse0, - ExecutionArguments::isParseComplete, - () -> args.parseAttempts++ - ); - } - private CompletionStage parse0(@NotNull ExecutionArguments args) { - if(args.parseAttempts > MAX_PARSE_ATTEMPTS) { - logger.debug("Parse attempts exceeded {}", MAX_PARSE_ATTEMPTS); - return CompletableFuture.failedFuture( - new EdgeDBException("Failed to parse query after " + args.parseAttempts + " attempts") - ); - } - - logger.debug("Starting to parse... attempt {}/{}", args.parseAttempts + 1, MAX_PARSE_ATTEMPTS); - - return getDuplexer().duplexAndSync(args.toParsePacket(), (result) -> { - logger.trace("parse duplex result: {}", result.packet.getMessageType()); - switch (result.packet.getMessageType()) { - case ERROR_RESPONSE: - var err = result.packet.as(ErrorResponse.class); - logger.debug("handling error: {}", err.errorCode); - handleCommandError(args, result, err); - return CompletableFuture.completedFuture(null); - case COMMAND_DATA_DESCRIPTION: - var commandDescriptor = result.packet.as(CommandDataDescription.class); - - logger.debug("parsing command data description"); - - if(!Objects.equals(args.capabilities, commandDescriptor.capabilities)) { - logger.debug( - "actual capabilities differ from the provided ones: provided: {}. actual: {}", - args.capabilities, - commandDescriptor.capabilities - ); - args.actualCapabilities = commandDescriptor.capabilities; - } - - if(args.cardinality != commandDescriptor.cardinality) { - logger.debug( - "actual cardinality differs from the provided one: provided: {}. actual: {}", - args.cardinality, - commandDescriptor.cardinality - ); - args.actualCardinality = commandDescriptor.cardinality; - } - - args.codecs = new CodecBuilder.QueryCodecs( - commandDescriptor.inputTypeDescriptorId, - CodecBuilder.buildCodec( - commandDescriptor.inputTypeDescriptorId, - commandDescriptor.inputTypeDescriptorBuffer - ), - commandDescriptor.outputTypeDescriptorId, - CodecBuilder.buildCodec( - commandDescriptor.outputTypeDescriptorId, - commandDescriptor.outputTypeDescriptorBuffer - ) - ); - - logger.debug( - "updating codec query cache key {} with I:{} O:{}", - args.getCacheKey(), - commandDescriptor.inputTypeDescriptorId, - commandDescriptor.outputTypeDescriptorId - ); - - CodecBuilder.updateCachedCodecs( - args.getCacheKey(), - commandDescriptor.inputTypeDescriptorId, - commandDescriptor.outputTypeDescriptorId - ); - break; - case STATE_DATA_DESCRIPTION: - updateStateCodec(result, args); - break; - case READY_FOR_COMMAND: - var ready = result.packet.as(ReadyForCommand.class); - setTransactionState(ready.transactionState); - args.completedParse = args.codecs != null; - result.finishDuplexing(); - } - - return CompletableFuture.completedFuture(null); - }); + public void setSuggestedPoolConcurrency(long value) { + this.suggestedPoolConcurrency = value; } - private CompletionStage execute(@NotNull ExecutionArguments args) { - return runWithAttempts( - args, - this::execute0, - ExecutionArguments::isExecuteComplete, - () -> args.parseAttempts++ - ); + public @NotNull CodecContext getCodecContext() { + return this.codecContext; } - private CompletionStage execute0(@NotNull ExecutionArguments args) { - if(args.parseAttempts > 2) { - return CompletableFuture.failedFuture( - new EdgeDBException("Failed to parse query after " + args.parseAttempts + " attempts") - ); - } - - if(!(args.codecs.inputCodec instanceof ArgumentCodec)) { - return CompletableFuture.failedFuture( - new MissingCodecException(String.format( - "Cannot encode arguments, %s is not a valid argument codec", - args.codecs.inputCodec) - ) - ); - } - - try { - return getDuplexer().duplexAndSync(args.toExecutePacket(), (result) -> { - switch (result.packet.getMessageType()) { - case DATA: - var data = result.packet.as(Data.class); - assert data.payloadBuffer != null; - // retain the data buffer once, so it's available for the - // consumer of data, since after this duplex step, `Data` and - // its children (buffers) are freed. - data.payloadBuffer.retain(); - args.data.add(data); - break; - case STATE_DATA_DESCRIPTION: - updateStateCodec(result, args); - break; - case ERROR_RESPONSE: - var err = result.packet.as(ErrorResponse.class); - handleCommandError(args, result, err); - break; - case READY_FOR_COMMAND: - var ready = result.packet.as(ReadyForCommand.class); - setTransactionState(ready.transactionState); - args.completedExecute = true; - result.finishDuplexing(); - break; - } - return CompletableFuture.completedFuture(null); - }); - } catch (OperationNotSupportedException | EdgeDBException e) { - return CompletableFuture.failedFuture(e); - } + public UUID getStateDescriptorId() { + return this.stateDescriptorId; } - - private CompletionStage runWithAttempts( - ExecutionArguments args, - @NotNull Function> delegate, - @NotNull Predicate completedPredicate, - @NotNull Runnable incrementer - ) { - return delegate.apply(args) - .thenCompose((v) -> { - if(!completedPredicate.test(args)) { - incrementer.run(); - return runWithAttempts(args, delegate, completedPredicate, incrementer); - } - - return CompletableFuture.completedFuture(null); - }); + public void setStateDescriptorId(UUID id) { + this.stateDescriptorId = id; } - private void handleCommandError(@NotNull ExecutionArguments args, Duplexer.@NotNull DuplexResult result, @NotNull ErrorResponse err) { - if(err.errorCode == ErrorCode.STATE_MISMATCH_ERROR) { - logger.debug("Has updated state?: {}", args.stateUpdated); - // should have new state - if(!args.stateUpdated) { - result.finishExceptionally( - "Failed to properly encode state data, this is a bug", - EdgeDBException::new - ); - } - } - else { - result.finishExceptionally(err, args.query, ErrorResponse::toException); - } + @SuppressWarnings("rawtypes") + public void setStateCodec(@Nullable Codec codec) { + this.stateCodec = codec; } - private void updateStateCodec(Duplexer.@NotNull DuplexResult result, @NotNull ExecutionArguments args) { - var stateDescriptor = result.packet.as(StateDataDescription.class); - var codec = CodecBuilder.getCodec(stateDescriptor.typeDescriptorId, Map.class); - - if(codec == null) { - try { - codec = CodecBuilder.buildCodec( - stateDescriptor.typeDescriptorId, - stateDescriptor.typeDescriptorBuffer, - Map.class - ); - } catch (EdgeDBException | OperationNotSupportedException e) { - result.finishExceptionally("Failed to parse state codec", e, EdgeDBException::new); - } - } - - stateCodec = codec; - stateDescriptorId = stateDescriptor.typeDescriptorId; - args.stateUpdated = true; - - try { - args.setStateData(serializeState()); - } catch (OperationNotSupportedException | EdgeDBException e) { - result.finishExceptionally("Failed to serialize state", e, EdgeDBException::new); - } + private static class ExecutionState { + public int attempts; } - public final CompletionStage executeQuery( - @NotNull ExecutionArguments args + public final CompletionStage executeQuery( + @NotNull QueryParameters args ) { logger.debug("Execute request: is connected? {}", getDuplexer().isConnected()); if(!getDuplexer().isConnected()) { @@ -306,99 +100,86 @@ public final CompletionStage executeQuery( } final var hasReleased = new AtomicBoolean(); + final var executionState = new ExecutionState(); return CompletableFuture.runAsync(() -> { try { + logger.debug("acquiring query semaphore..."); this.querySemaphore.acquire(); + logger.debug("query semaphore acquired"); } catch (InterruptedException e) { throw new RuntimeException(e); } }) - .thenCompose((v) -> { - logger.debug("Entering execute step"); - - CompletionStage task; - - try { - var cacheKey = args.getCacheKey(); - - args.setStateData(serializeState()); - - var codecInfo = CodecBuilder.getCachedCodecs(cacheKey); - - if(codecInfo == null) { - task = parse(args).thenCompose((u) -> execute(args)); - } else { - args.codecs = codecInfo; + .thenCompose((v) -> executeQuery0(args,executionState)) + .whenComplete((v,e) -> { + if(!hasReleased.get()) { + this.querySemaphore.release(); + } + }); + } - logger.debug("Codecs found for query: {} {}", codecInfo.inputCodec, codecInfo.outputCodec); + private CompletionStage executeQuery0(@NotNull QueryParameters args, ExecutionState state) { + return exceptionallyCompose( + protocolProvider + .parseQuery(args) + .thenCompose(parseResult -> protocolProvider.executeQuery(args, parseResult)), + e -> { + logger.debug("got exception in execute step", e); - task = execute(args); - } - } catch (OperationNotSupportedException | EdgeDBException e) { - throw new RuntimeException(e); + if(e instanceof EdgeDBErrorException && !((EdgeDBException)e).shouldReconnect && !((EdgeDBException)e).shouldRetry) { + return CompletableFuture.failedFuture(e); } - return exceptionallyCompose(task, e -> { - if(e instanceof EdgeDBErrorException && !((EdgeDBException)e).shouldReconnect && !((EdgeDBException)e).shouldRetry) { - return CompletableFuture.failedFuture(e); + if(e instanceof EdgeDBException) { + var edbException = (EdgeDBException) e; + if(state.attempts > getConfig().getMaxConnectionRetries()) { + return CompletableFuture.failedFuture( + new EdgeDBException( + String.format( + "Failed to execute query after %d attempts", + state.attempts + ), + e + ) + ); } - if(e instanceof EdgeDBException) { - var edbException = (EdgeDBException) e; - if(edbException.shouldRetry && !args.isRetry) { - this.querySemaphore.release(); - hasReleased.set(true); - var newArgs = args.deriveNew(); - newArgs.isRetry = true; - return executeQuery(newArgs); - } + if(edbException.shouldRetry) { + state.attempts++; + logger.debug("Retrying with attempts now at {}", state.attempts); - if(edbException.shouldReconnect && !args.isRetry) { - var newArgs = args.deriveNew(); - newArgs.isRetry = true; - - return this.reconnect() - .thenAccept(x -> { - this.querySemaphore.release(); - hasReleased.set(true); - }) - .thenCompose(y -> executeQuery(newArgs)); - } + return executeQuery0(args, state); } - var sb = new StringBuilder("Failed to execute query"); + if(edbException.shouldReconnect) { + state.attempts++; + logger.debug("Reconnecting and retrying with attempts now at {}", state.attempts); - if(args.isRetry) { - sb.append(" after retrying once"); + return this.reconnect() + .thenCompose(y -> executeQuery0(args, state)); } - - return CompletableFuture.failedFuture(new EdgeDBException(sb.toString(), e)); - }); - - }) - .whenComplete((v,e) -> { - if(!hasReleased.get()) { - this.querySemaphore.release(); } - }); + + return CompletableFuture.failedFuture(new EdgeDBException("Failed to execute query", e)); + } + ); } @Override public CompletionStage execute( @NotNull String query, - @Nullable Map args, + @Nullable Map args, EnumSet capabilities ) { - return executeQuery(new ExecutionArguments( + return executeQuery(new QueryParameters( query, args, - Cardinality.MANY, capabilities, + Cardinality.MANY, IOFormat.NONE, - false, false - )); + )).thenApply(r -> null); } @Override @@ -408,39 +189,37 @@ public CompletionStage> query( @Nullable Map args, @NotNull EnumSet capabilities ) { - // TODO: does this query result require implicit type names - final var executeArgs = new ExecutionArguments( + return executeQuery(new QueryParameters( query, args, - Cardinality.MANY, capabilities, + Cardinality.MANY, IOFormat.BINARY, - false, TypeBuilder.requiredImplicitTypeNames(cls) - ); + )).thenCompose(result -> { + var arr = new ArrayList(result.data.size()); - return executeQuery(executeArgs) - .thenCompose((v) -> { - var arr = new ArrayList(executeArgs.data.size()); - - for(int i = 0; i != executeArgs.data.size(); i++) { - try { - arr.add(i, ObjectBuilder.buildResult( + for(int i = 0; i != result.data.size(); i++) { + try { + arr.add( + i, + ObjectBuilder.buildResult( this, - executeArgs.codecs.outputCodec, - executeArgs.data.get(i), + result.codec, + result.data.get(i), cls - )); - } catch (EdgeDBException | OperationNotSupportedException e) { - return CompletableFuture.failedFuture(e); - } finally { - // free the buffer - executeArgs.data.get(i).close(); - } - } + ) + ); + } catch (EdgeDBException | OperationNotSupportedException e) { + return CompletableFuture.failedFuture(e); + } finally { + // free the buffer + result.data.get(i).release(); + } + } - return CompletableFuture.completedFuture(Collections.unmodifiableList(arr)); - }); + return CompletableFuture.completedFuture(Collections.unmodifiableList(arr)); + }); } @Override @@ -450,19 +229,43 @@ public CompletionStage querySingle( @Nullable Map args, @NotNull EnumSet capabilities ) { - // TODO: does this query result require implicit type names - final var executeArgs = new ExecutionArguments( + return executeQuery(new QueryParameters( query, args, - Cardinality.MANY, capabilities, + Cardinality.MANY, IOFormat.BINARY, - false, TypeBuilder.requiredImplicitTypeNames(cls) - ); + )).thenApply(result -> { + if(result.data.size() == 0) { + return null; + } + + if(result.data.size() > 1) { + for (var buffer : result.data) { + buffer.release(); + } + + throw new CompletionException( + new ResultCardinalityMismatchException(Cardinality.AT_MOST_ONE, Cardinality.MANY) + ); + } + + try { + return ObjectBuilder.buildResult( + this, + result.codec, + result.data.get(0), + cls + ); + } catch (EdgeDBException | OperationNotSupportedException e) { + throw new CompletionException(e); + } + finally { + result.data.get(0).release(); + } + }); - return executeQuery(executeArgs) - .thenCompose((v) -> deserializeSingleResult(cls, executeArgs, Cardinality.AT_MOST_ONE)); } @Override @@ -472,19 +275,39 @@ public CompletionStage queryRequiredSingle( @Nullable Map args, @NotNull EnumSet capabilities ) { - // TODO: does this query result require implicit type names - final var executeArgs = new ExecutionArguments( + + return executeQuery(new QueryParameters( query, args, - Cardinality.MANY, capabilities, + Cardinality.MANY, IOFormat.BINARY, - false, TypeBuilder.requiredImplicitTypeNames(cls) - ); + )).thenApply(result -> { + if(result.data.size() != 1) { + for (var buffer : result.data) { + buffer.release(); + } - return executeQuery(executeArgs) - .thenCompose((v) -> deserializeSingleResult(cls, executeArgs, Cardinality.ONE)); + throw new CompletionException( + new ResultCardinalityMismatchException(Cardinality.ONE, Cardinality.MANY) + ); + } + + try { + return ObjectBuilder.buildResult( + this, + result.codec, + result.data.get(0), + cls + ); + } catch (EdgeDBException | OperationNotSupportedException e) { + throw new CompletionException(e); + } + finally { + result.data.get(0).release(); + } + }); } @Override @@ -493,128 +316,84 @@ public CompletionStage queryJson( @Nullable Map args, @NotNull EnumSet capabilities ) { - final var executeArgs = new ExecutionArguments( + return executeQuery(new QueryParameters( query, args, - Cardinality.MANY, capabilities, + Cardinality.MANY, IOFormat.JSON, - false, false - ); + )).thenApply(result -> { + if(result.data.size() > 1) { + for (var buffer : result.data) { + buffer.release(); + } + + throw new CompletionException( + new ResultCardinalityMismatchException(Cardinality.AT_MOST_ONE, Cardinality.MANY) + ); + } + + if(result.data.size() == 0) { + return new Json("[]"); + } - return executeQuery(executeArgs) - .thenCompose(v -> deserializeSingleResult(String.class, executeArgs, Cardinality.AT_MOST_ONE)) - .thenApply(Json::new); + try { + return new Json( + (String)Objects.requireNonNull(Codec.deserializeFromBuffer( + result.codec, + Objects.requireNonNull(result.data.get(0)), + this.codecContext + )) + ); + } catch (EdgeDBException | OperationNotSupportedException e) { + throw new CompletionException(e); + } + finally { + result.data.get(0).release(); + } + }); } - @SuppressWarnings("unchecked") @Override public CompletionStage> queryJsonElements(@NotNull String query, @Nullable Map args, @NotNull EnumSet capabilities) { - final var executeArgs = new ExecutionArguments( + return executeQuery(new QueryParameters( query, args, - Cardinality.MANY, capabilities, + Cardinality.MANY, IOFormat.JSON_ELEMENTS, - false, false - ); - - return executeQuery(executeArgs) - .thenApply(v -> { - var result = new Json[executeArgs.data.size()]; - - for(int i = 0; i != executeArgs.data.size(); i++) { - try { - result[i] = new Json( - (String) Objects.requireNonNull(Codec.deserializeFromBuffer( - executeArgs.codecs.outputCodec, - Objects.requireNonNull(executeArgs.data.get(i).payloadBuffer), - this.codecContext - )) - ); - } catch (EdgeDBException | OperationNotSupportedException e) { - throw new CompletionException(e); - } - } - - return List.of(result); - }); - } + )).thenApply(result -> { + try { + var data = new Json[result.data.size()]; - @SuppressWarnings("unchecked") - private @NotNull CompletionStage deserializeSingleResult(@NotNull Class cls, @NotNull ExecutionArguments args, @NotNull Cardinality expected) { - try { - switch (args.format) { - case JSON: - if(args.data.size() == 1) { - try { - return CompletableFuture.completedFuture( - Codec.deserializeFromBuffer( - (Codec)args.codecs.outputCodec, - Objects.requireNonNull(args.data.get(0).payloadBuffer), - this.codecContext - ) - ); - } - catch (Exception x) { - return CompletableFuture.failedFuture(x); - } + for(int i = 0; i != result.data.size(); i++) { + try { + data[i] = new Json( + (String) Objects.requireNonNull(Codec.deserializeFromBuffer( + result.codec, + Objects.requireNonNull(result.data.get(i)), + this.codecContext + )) + ); + } catch (EdgeDBException | OperationNotSupportedException e) { + throw new CompletionException(e); } + } - return CompletableFuture.completedFuture((T)"[]"); - case BINARY: - switch (expected) { - case ONE: - case AT_MOST_ONE: - if(expected == Cardinality.ONE - ? args.data.size() != 1 - : args.data.size() > 1 - ) { - return CompletableFuture.failedFuture( - new ResultCardinalityMismatchException( - expected, - args.data.size() > 1 - ? Cardinality.MANY - : Cardinality.AT_MOST_ONE - ) - ); - } - - try { - return CompletableFuture.completedFuture( - args.data.size() == 0 - ? null - : ObjectBuilder.buildResult( - this, - args.codecs.outputCodec, - args.data.get(0), - cls - ) - ); - } catch (EdgeDBException | OperationNotSupportedException e) { - return CompletableFuture.failedFuture(e); - } - default: - return CompletableFuture.failedFuture( - new EdgeDBException("Unsupported cardinality result " + expected) - ); - } - default: - return CompletableFuture.failedFuture( - new EdgeDBException("Unsupported IO format" + args.format) - ); + return List.of(data); } - } - finally { - for(var data : args.data) { - data.close(); + finally { + for (var buffer : result.data) { + buffer.release(); + } } - } + }); } - private @Nullable ByteBuf serializeState() throws OperationNotSupportedException, EdgeDBException { + @Nullable + public ByteBuf serializeState() throws OperationNotSupportedException, EdgeDBException { if(this.stateCodec == null) { return null; } @@ -623,235 +402,23 @@ public CompletionStage> queryJsonElements(@NotNull String query, @Nul return Codec.serializeToBuffer(this.stateCodec, data, this.codecContext); } - private CompletionStage handlePacket( - @NotNull Receivable packet - ) { - logger.debug("Processing packet {}", packet.getMessageType()); - - try { - switch (packet.getMessageType()) { - case SERVER_HANDSHAKE: - var handshake = (ServerHandshake)packet; - - if(handshake.majorVersion.compareTo(PROTOCOL_MAJOR_VERSION) != 0 || - handshake.minorVersion.compareTo(PROTOCOL_MINOR_VERSION) < 0 - ) { - logger.error( - "The server requested protocol version {}.{} but the currently installed client only " + - "supports {}.{}. Please switch to a different client version that supports the " + - "requested protocol.", - handshake.majorVersion, handshake.majorVersion, - PROTOCOL_MAJOR_VERSION, PROTOCOL_MINOR_VERSION - ); - return this.disconnect(); - } else if(handshake.minorVersion.compareTo(PROTOCOL_MINOR_VERSION) > 0) { - logger.warn( - "The server requested protocol version {}.{} but the currently installed client only " + - "supports {}.{}. Functionality may be limited and bugs may arise, please switch to " + - "a different client version that supports the requested protocol.", - handshake.majorVersion, handshake.majorVersion, - PROTOCOL_MAJOR_VERSION, PROTOCOL_MINOR_VERSION - ); - } - break; - case ERROR_RESPONSE: - var error = (ErrorResponse)packet; - - logger.error("{} - {}: {}", error.severity, error.errorCode, error.message); + public boolean tryNegotiateProtocol(UShort major, UShort minor) { + logger.info("Server requested protocol {}.{}, current: {}", major, major, protocolProvider.getVersion()); - var exc = error.toException(); - - if(!readyPromise.isDone()) { - readyPromise.completeExceptionally(exc); - } - return CompletableFuture.failedFuture(exc); - case AUTHENTICATION: - var auth = (AuthenticationStatus)packet; - if(auth.authStatus == AuthStatus.AUTHENTICATION_REQUIRED_SASL_MESSAGE) { - return startSASLAuthentication(auth); - } else if (auth.authStatus != AuthStatus.AUTHENTICATION_OK) { - throw new UnexpectedMessageException( - "Expected AuthenticationRequiredSASLMessage, got " + auth.authStatus - ); - } - break; - case SERVER_KEY_DATA: - // eventually used - byte[] serverKey = new byte[32]; - ((ServerKeyData)packet).keyData.readBytes(serverKey); - break; - case STATE_DATA_DESCRIPTION: - var stateDescriptor = (StateDataDescription)packet; - - var codec = CodecBuilder.getCodec(stateDescriptor.typeDescriptorId, Map.class); - - if(codec == null) { - assert stateDescriptor.typeDescriptorBuffer != null; - - var reader = new PacketReader(stateDescriptor.typeDescriptorBuffer); - codec = CodecBuilder.buildCodec(stateDescriptor.typeDescriptorId, reader, Map.class); - } - - this.stateCodec = codec; - this.stateDescriptorId = stateDescriptor.typeDescriptorId; - break; - case PARAMETER_STATUS: - parseServerSettings((ParameterStatus) packet); - break; - case LOG_MESSAGE: - var msg = (LogMessage)packet; - var formatted = msg.format(); - switch (msg.severity) { - case INFO: - case NOTICE: - logger.info(formatted); - break; - case DEBUG: - logger.debug(formatted); - break; - case WARNING: - logger.warn(formatted); - break; - } - break; - } - } - catch (Exception x) { - logger.debug("Processing failed", x); - return CompletableFuture.failedFuture(x); + var newProvider = ProtocolProvider.PROVIDERS.get(ProtocolVersion.of(major, minor)); + if(newProvider != null) { + this.protocolProvider = newProvider.apply(this); + ProtocolProvider.updateProviderFor(this, this.protocolProvider); + return true; } - - logger.debug("Processing pass-through to completed result"); - - return CompletableFuture.completedFuture(null); + return false; } - private void parseServerSettings(@NotNull ParameterStatus status) throws EdgeDBException, OperationNotSupportedException { - switch (status.name) { - case "suggested_pool_concurrency": - assert status.value != null; - - var buffer = new byte[status.value.readableBytes()]; - status.value.readBytes(buffer); - var str = new String(buffer, StandardCharsets.UTF_8); - - try { - this.suggestedPoolConcurrency = Long.parseLong(str); - } catch (NumberFormatException x) { - logger.error("suggested_pool_concurrency wasn't in a numeric format", x); - } - break; - case "system_config": - assert status.value != null; - - var reader = new PacketReader(status.value); - var descriptorLength = reader.readInt32() - 16; - var descriptorId = reader.readUUID(); - - var codec = CodecBuilder.getCodec(descriptorId, Map.class); - - if(codec == null) { - var descriptorReader = new PacketReader(reader.readBytes(descriptorLength)); - codec = CodecBuilder.buildCodec(descriptorId, descriptorReader, Map.class); - - if(codec == null) { - throw new MissingCodecException("Failed to build codec for system_config"); - } - } - - reader.skip(BinaryProtocolUtils.INT_SIZE); // discard length - - //noinspection unchecked - this.rawServerConfig = codec.deserialize(reader, codecContext); - break; - } - } - - private CompletionStage startSASLAuthentication(@NotNull AuthenticationStatus authStatus) throws ScramException { - this.isIdle = false; - - final var scram = new Scram(); - - assert authStatus.authenticationMethods != null; - - var method = authStatus.authenticationMethods[0]; - - assert method != null; - - if(!method.equals("SCRAM-SHA-256")) { - throw new ScramException("The only supported method is SCRAM-SHA-256, but the server wants " + method); - } - - var connection = getConnectionArguments(); - var initialMessage = scram.buildInitialMessagePacket(connection.getUsername(), method); - - AtomicReference signature = new AtomicReference<>(new byte[0]); - - try{ - return getDuplexer().duplex(initialMessage, (state) -> { - logger.debug("Authentication duplex: M:{}", state.packet.getMessageType()); - try { - switch (state.packet.getMessageType()) { - case AUTHENTICATION: - var auth = (AuthenticationStatus)state.packet; - - logger.debug("Processing auth part: {}", auth.authStatus); - - switch (auth.authStatus) { - case AUTHENTICATION_SASL_CONTINUE: - var result = scram.buildFinalMessage(auth, connection.getPassword()); - signature.set(result.signature); - return getDuplexer().send(result.buildPacket()); - case AUTHENTICATION_SASL_FINAL: - var key = Scram.parseServerFinalMessage(auth); - - if(!Arrays.equals(signature.get(), key)) { - logger.error( - "The SCRAM signature didn't match. ours: {}, servers: {}.", - signature.get(), - key - ); - throw new InvalidSignatureException(); - } - break; - case AUTHENTICATION_OK: - logger.debug("Completing auth duplex"); - state.finishDuplexing(); - this.isIdle = false; - break; - default: - throw new UnexpectedMessageException( - "Expected continue or final but got " + auth.authStatus - ); - } - break; - case ERROR_RESPONSE: - throw ((ErrorResponse)state.packet).toException(); - default: - logger.error( - "Unexpected message. expected: {} actual: {}", - ServerMessageType.AUTHENTICATION, - state.packet.getMessageType() - ); - throw new CompletionException( - new UnexpectedMessageException( - ServerMessageType.AUTHENTICATION, - state.packet.getMessageType() - ) - ); - } - } // TODO: should reconnect & should retry exceptions - catch (Exception err) { - this.isIdle = false; - state.finishExceptionally(err); - return CompletableFuture.failedFuture(err); - } - - return CompletableFuture.completedFuture(null); - }); - } - catch (Throwable x) { - return CompletableFuture.failedFuture(x); + public void cancelReadyState(@Nullable Exception error) { + if(error == null) { + readyPromise.cancel(true); + } else { + readyPromise.completeExceptionally(error); } } @@ -873,24 +440,44 @@ public CompletionStage connect() { } private CompletionStage doClientHandshake() { - return getDuplexer().readNext() - .thenCompose(packet -> { - logger.debug("Processing handshake step with packet: {}", packet == null ? "NULL" : packet.getMessageType()); + return exceptionallyCompose( + getDuplexer() + .readNext() + .thenCompose(protocolProvider::processMessage) + .thenCompose(v -> { + if(protocolProvider.getPhase() != ProtocolPhase.COMMAND) { + logger.debug("Rerunning handshake, phase: {}", protocolProvider.getPhase()); + return doClientHandshake(); + } - if(packet == null) { - return CompletableFuture.failedFuture(new UnexpectedDisconnectException()); - } + return CompletableFuture.completedFuture((Void)null); + }), + error -> { + if(error instanceof EdgeDBErrorException && ((EdgeDBException)error).shouldReconnect) { + if(getConfig().getConnectionRetryMode() == ConnectionRetryMode.NEVER_RETRY) { + return CompletableFuture.failedFuture(new ConnectionFailedException(error)); + } + + if(this.connectionAttempts < getConfig().getMaxConnectionRetries()) { + this.connectionAttempts++; - if(packet instanceof ReadyForCommand) { - logger.debug("Dispatching client ready"); - this.readyPromise.complete(null); - return dispatchReady(); + logger.warn("Attempting to reconnect... {}/{}", this.connectionAttempts, getConfig().getMaxConnectionRetries(), error); + + return disconnect() + .thenCompose(v -> { + this.connectionSemaphore.release(); + return connect(); + }); + } else { + logger.error("Failed to establish a connection after {} attempts", this.connectionAttempts, error); + this.connectionAttempts = 0; + return CompletableFuture.failedFuture(new ConnectionFailedException(this.connectionAttempts, error)); + } } - logger.debug("Transitioning packet handling to this::handlePacket"); - return composeWith(packet, this::handlePacket) - .thenCompose((v) -> doClientHandshake()); - }); + return CompletableFuture.failedFuture(error); + } + ); } @Override @@ -906,24 +493,7 @@ private CompletionStage connectInternal() { getDuplexer().reset(); return retryableConnect() - .thenApply(v -> { - var connection = getConnectionArguments(); - return connection.getSecretKey() != null - ? new ConnectionParam[] { - new ConnectionParam("user", connection.getUsername()), - new ConnectionParam("database", connection.getDatabase()), - new ConnectionParam("secret_key", connection.getSecretKey()) - } : new ConnectionParam[] { - new ConnectionParam("user", connection.getUsername()), - new ConnectionParam("database", connection.getDatabase()) - }; - }) - .thenApply(connectionParams -> new ClientHandshake( - PROTOCOL_MAJOR_VERSION, - PROTOCOL_MINOR_VERSION, - connectionParams, - new ProtocolExtension[0] - )) + .thenApply(v -> protocolProvider.handshake()) .thenCompose(getDuplexer()::send); } @@ -957,7 +527,7 @@ private CompletionStage retryableConnect() { } } - protected abstract void setTransactionState(TransactionState state); + public abstract void setTransactionState(TransactionState state); protected abstract CompletionStage openConnection(); protected abstract CompletionStage closeConnection(); @@ -966,139 +536,4 @@ private CompletionStage retryableConnect() { public boolean isConnected() { return getDuplexer().isConnected(); } - - public final class ExecutionArguments { - public final String query; - public final Map args; - public final Cardinality cardinality; - public final @Nullable EnumSet capabilities; - public final IOFormat format; - public boolean isRetry; - public final boolean implicitTypeNames; - - public Cardinality actualCardinality; - public @Nullable EnumSet actualCapabilities; - - private @Nullable Long cacheKey; - - public CodecBuilder.QueryCodecs codecs; - - public final @NotNull List data; - - private boolean completedParse; - private byte parseAttempts; - - private boolean completedExecute; - - private boolean stateUpdated; - private ByteBuf stateData; - - public ExecutionArguments( - String query, - Map args, - Cardinality cardinality, - @Nullable EnumSet capabilities, - IOFormat format, - boolean isRetry, - boolean implicitTypeNames - ) { - this.data = new ArrayList<>(); - this.query = query; - this.args = args; - this.cardinality = cardinality; - this.capabilities = capabilities; - this.format = format; - this.isRetry = isRetry; - this.implicitTypeNames = implicitTypeNames; - - this.actualCardinality = cardinality; - this.actualCapabilities = capabilities; - } - - public @NotNull ExecutionArguments deriveNew() { - return new ExecutionArguments( - this.query, - this.args, - this.cardinality, - this.capabilities, - this.format, - this.isRetry, - this.implicitTypeNames - ); - } - - public boolean isParseComplete() { - return this.completedParse; - } - - public boolean isExecuteComplete() { - return this.completedExecute; - } - - public void setStateData(ByteBuf state) { - this.stateData = state; - } - - public synchronized long getCacheKey() { - if(cacheKey == null) { - return cacheKey = CodecBuilder.getCacheKey(this.query, this.cardinality, this.format); - } - - return cacheKey; - } - - public @NotNull EnumSet getCompilationFlags() { - var flags = EnumSet.of(CompilationFlags.NONE); - - if(getConfig().getImplicitTypeIds()) { - flags.add(CompilationFlags.IMPLICIT_TYPE_IDS); - } - - if(implicitTypeNames) { - flags.add(CompilationFlags.IMPLICIT_TYPE_NAMES); - } - - if(!getConfig().getExplicitObjectIds()) { - flags.add(CompilationFlags.EXPLICIT_OBJECT_IDS); - } - - return flags; - } - - public long getImplicitLimit() { - return getConfig().getImplicitLimit(); - } - - public @NotNull Parse toParsePacket() { - return new Parse( - capabilities, - getCompilationFlags(), - format, - cardinality, - query, - getImplicitLimit(), - stateDescriptorId, - stateData - ); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public @NotNull Execute toExecutePacket() throws OperationNotSupportedException, EdgeDBException { - assert codecs != null; - - return new Execute( - capabilities, - getCompilationFlags(), - getImplicitLimit(), - format, - cardinality, - query, - stateDescriptorId, - stateData, - codecs.inputCodecId, - codecs.outputCodecId, - ArgumentCodec.serializeToBuffer((ArgumentCodec) codecs.inputCodec, args, codecContext) - ); - } - } } diff --git a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBHttpClient.java b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBHttpClient.java index 17197fb4..7c44ea71 100644 --- a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBHttpClient.java +++ b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBHttpClient.java @@ -209,12 +209,12 @@ public synchronized URI getExecUri() { } @Override - protected Duplexer getDuplexer() { + public Duplexer getDuplexer() { return this.duplexer; } @Override - protected void setTransactionState(TransactionState state) { + public void setTransactionState(TransactionState state) { // invalid for this client } diff --git a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBTCPClient.java b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBTCPClient.java index 96b22f2c..8579916f 100644 --- a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBTCPClient.java +++ b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBTCPClient.java @@ -73,7 +73,7 @@ protected void initChannel(@NotNull SocketChannel ch) throws Exception { // edgedb-binary protocol and duplexer pipeline.addLast( - PacketSerializer.createDecoder(), + PacketSerializer.createDecoder(EdgeDBTCPClient.this), PacketSerializer.createEncoder() ); @@ -85,12 +85,12 @@ protected void initChannel(@NotNull SocketChannel ch) throws Exception { } @Override - protected @NotNull ChannelDuplexer getDuplexer() { + public @NotNull ChannelDuplexer getDuplexer() { return this.duplexer; } @Override - protected void setTransactionState(TransactionState state) { + public void setTransactionState(TransactionState state) { this.transactionState = state; } diff --git a/src/driver/src/main/java/com/edgedb/driver/util/Scram.java b/src/driver/src/main/java/com/edgedb/driver/util/Scram.java index 1a8cffa5..78a059c4 100644 --- a/src/driver/src/main/java/com/edgedb/driver/util/Scram.java +++ b/src/driver/src/main/java/com/edgedb/driver/util/Scram.java @@ -1,8 +1,8 @@ package com.edgedb.driver.util; -import com.edgedb.driver.binary.packets.receivable.AuthenticationStatus; -import com.edgedb.driver.binary.packets.sendables.AuthenticationSASLInitialResponse; -import com.edgedb.driver.binary.packets.sendables.AuthenticationSASLResponse; +import com.edgedb.driver.binary.protocol.v1.receivables.AuthenticationStatus; +import com.edgedb.driver.binary.protocol.v1.sendables.AuthenticationSASLInitialResponse; +import com.edgedb.driver.binary.protocol.v1.sendables.AuthenticationSASLResponse; import com.edgedb.driver.exceptions.ScramException; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; diff --git a/src/driver/src/test/java/shared/SharedTestsRunner.java b/src/driver/src/test/java/shared/SharedTestsRunner.java index 4cb77e19..0d96e59f 100644 --- a/src/driver/src/test/java/shared/SharedTestsRunner.java +++ b/src/driver/src/test/java/shared/SharedTestsRunner.java @@ -4,9 +4,9 @@ import com.edgedb.driver.EdgeDBClientConfig; import com.edgedb.driver.binary.builders.ObjectBuilder; import com.edgedb.driver.binary.codecs.Codec; -import com.edgedb.driver.binary.packets.receivable.Data; -import com.edgedb.driver.binary.packets.shared.Cardinality; -import com.edgedb.driver.binary.packets.shared.IOFormat; +import com.edgedb.driver.binary.protocol.QueryParameters; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.IOFormat; import com.edgedb.driver.clients.BaseEdgeDBClient; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.datatypes.RelativeDuration; @@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.netty.buffer.ByteBuf; import shared.json.CDurationDeserializer; import shared.json.CPeriodDeserializer; import shared.json.CRelativeDurationDeserializer; @@ -31,10 +32,7 @@ import java.nio.file.Path; import java.time.Duration; import java.time.Period; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletionStage; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -120,7 +118,7 @@ public static void Run(Path path) { try { // store reader index before build var readerIndexes = executionResult.data.stream() - .mapToInt(v -> v.payloadBuffer.readerIndex()) + .mapToInt(ByteBuf::readerIndex) .toArray(); value = buildResult(clientHandle, resultType, executionResult); @@ -128,7 +126,7 @@ public static void Run(Path path) { // restore reader indexes post-build IntStream.range(0, executionResult.data.size()) .mapToObj(k -> Map.entry(executionResult.data.get(k), readerIndexes[k])) - .forEach(v -> v.getKey().payloadBuffer.readerIndex(v.getValue())); + .forEach(v -> v.getKey().readerIndex(v.getValue())); } catch (EdgeDBException | OperationNotSupportedException e) { throw new RuntimeException(e); } @@ -150,7 +148,7 @@ private static Object buildResult(EdgeDBBinaryClient client, Class type, Bina var arr = (Object[])Array.newInstance(type, result.data.size()); for(int i = 0; i != result.data.size(); i++) { - var value = ObjectBuilder.buildResult(client, result.deserializer, result.data.get(i), type); + var value = ObjectBuilder.buildResult(client, result.deserializer, Objects.requireNonNull(result.data.get(i)), type); arr[i] = value; } @@ -159,12 +157,12 @@ private static Object buildResult(EdgeDBBinaryClient client, Class type, Bina if(result.data.size() == 0) return null; - return ObjectBuilder.buildResult(client, result.deserializer, result.data.get(0), type); + return ObjectBuilder.buildResult(client, result.deserializer, Objects.requireNonNull(result.data.get(0)), type); case ONE: if(result.data.size() != 1) throw new IllegalArgumentException("Missing data for result"); - return ObjectBuilder.buildResult(client, result.deserializer, result.data.get(0), type); + return ObjectBuilder.buildResult(client, result.deserializer, Objects.requireNonNull(result.data.get(0)), type); default: if(result.data.size() > 0) throw new IllegalArgumentException("Unknown cardinality path for remaining data"); @@ -190,10 +188,10 @@ private static CompletionStage getClientHandle() throws Invoca private static final class BinaryResult { public final Codec deserializer; - public final List data; + public final List data; public final Cardinality cardinality; - private BinaryResult(Codec deserializer, List data, Cardinality cardinality) { + private BinaryResult(Codec deserializer, List data, Cardinality cardinality) { this.deserializer = deserializer; this.data = data; this.cardinality = cardinality; @@ -223,19 +221,18 @@ private static BinaryResult executeQuery(EdgeDBBinaryClient client, QueryExecuti break; } - var executionArgs = client.new ExecutionArguments( + var executionArgs = new QueryParameters( query.value, args, - queryCard, query.getCapabilities(), + queryCard, query.getCardinality() == Cardinality.NO_RESULT ? IOFormat.NONE : IOFormat.BINARY, - false, false ); - client.executeQuery(executionArgs).toCompletableFuture().get(); + var result = client.executeQuery(executionArgs).toCompletableFuture().get(); - return new BinaryResult(executionArgs.codecs.outputCodec, executionArgs.data, executionArgs.cardinality); + return new BinaryResult(result.codec, result.data, executionArgs.cardinality); } } diff --git a/src/driver/src/test/java/shared/models/QueryExecutionArguments.java b/src/driver/src/test/java/shared/models/QueryExecutionArguments.java index 278e6654..239bd208 100644 --- a/src/driver/src/test/java/shared/models/QueryExecutionArguments.java +++ b/src/driver/src/test/java/shared/models/QueryExecutionArguments.java @@ -2,7 +2,7 @@ import com.edgedb.driver.Capabilities; import com.edgedb.driver.binary.PacketSerializer; -import com.edgedb.driver.binary.packets.shared.Cardinality; +import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.state.Session; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import shared.json.SessionDeserializer; From b532cda5a606af31189baa95bb840efeae80c096 Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Thu, 27 Jul 2023 14:55:32 -0300 Subject: [PATCH 02/10] working abstraction --- .../driver/binary/builders/CodecBuilder.java | 172 ++++++++++-------- .../binary/protocol/ProtocolProvider.java | 3 +- .../binary/protocol/ProtocolVersion.java | 6 + .../protocol/v1/V1ProtocolProvider.java | 50 +++-- .../driver/clients/EdgeDBBinaryClient.java | 10 +- 5 files changed, 145 insertions(+), 96 deletions(-) diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java index be803465..bc2b6df9 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java @@ -7,12 +7,14 @@ import com.edgedb.driver.binary.codecs.scalars.complex.BytesCodec; import com.edgedb.driver.binary.codecs.scalars.complex.DateTimeCodec; import com.edgedb.driver.binary.codecs.scalars.complex.RelativeDurationCodec; +import com.edgedb.driver.binary.protocol.ProtocolProvider; +import com.edgedb.driver.binary.protocol.ProtocolVersion; import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.binary.protocol.common.IOFormat; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.EdgeDBException; -import com.edgedb.driver.util.CollectionUtils; +import com.edgedb.driver.exceptions.MissingCodecException; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,66 +22,84 @@ import org.slf4j.LoggerFactory; import javax.naming.OperationNotSupportedException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; public final class CodecBuilder { + private static final class CodecCache { + public final ConcurrentMap> cache; + public final ConcurrentMap> codecPartsInstanceCache; + public final ConcurrentMap queryCodecsCache; + + public final ProtocolVersion version; + + + private CodecCache(ProtocolVersion version) { + this.version = version; + this.cache = new ConcurrentHashMap<>(16); + this.codecPartsInstanceCache = new ConcurrentHashMap<>(16); + this.queryCodecsCache = new ConcurrentHashMap<>(8); + } + } + private static final Logger logger = LoggerFactory.getLogger(CodecBuilder.class); public static final UUID NULL_CODEC_ID = new UUID(0L, 0L); public static final UUID INVALID_CODEC_ID = new UUID(Long.MAX_VALUE, Long.MAX_VALUE); - private static final @NotNull ConcurrentMap> codecPartsInstanceCache; - private static final @NotNull ConcurrentMap> codecCache; - private static final @NotNull ConcurrentMap queryCodecCache; + + private static final ConcurrentMap codecCaches; static { - codecPartsInstanceCache = new ConcurrentHashMap<>(16); - codecCache = new ConcurrentHashMap<>(32); - queryCodecCache = new ConcurrentHashMap<>(16); + codecCaches = new ConcurrentHashMap<>(2); } @SuppressWarnings("unchecked") - public static @Nullable Codec getCodec(UUID id, Class ignoredCls) { - return (Codec) getCodec(id); + public static @Nullable Codec getCodec(ProtocolProvider provider, UUID id, Class ignoredCls) { + return (Codec) getCodec(provider, id); } - public static @Nullable Codec getCodec(UUID id) { - var codec = codecCache.get(id); - return codec != null ? codec : getScalarCodec(id); + public static @Nullable Codec getCodec(ProtocolProvider provider, UUID id) { + var codec = codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new).cache.get(id); + return codec != null ? codec : getScalarCodec(provider, id); } - public static @NotNull Codec buildCodec(@NotNull UUID id, @Nullable ByteBuf buffer) throws EdgeDBException { + public static @NotNull Codec buildCodec(EdgeDBBinaryClient client, @NotNull UUID id, @Nullable ByteBuf buffer) throws EdgeDBException { if(id.equals(NULL_CODEC_ID) || buffer == null) { - return getOrCreateCodec(NULL_CODEC_ID, NullCodec::new); + return getOrCreateCodec(client.getProtocolProvider(), NULL_CODEC_ID, NullCodec::new); } var reader = new PacketReader(buffer); - return buildCodec(id, reader); + return buildCodec(client, id, reader); } @SuppressWarnings("unchecked") - public static @NotNull Codec buildCodec(@NotNull UUID id, @Nullable ByteBuf buffer, Class cls) throws EdgeDBException, OperationNotSupportedException { + public static @NotNull Codec buildCodec(EdgeDBBinaryClient client, @NotNull UUID id, @Nullable ByteBuf buffer, Class cls) throws EdgeDBException, OperationNotSupportedException { if(id.equals(NULL_CODEC_ID) || buffer == null) { - return (Codec)getOrCreateCodec(NULL_CODEC_ID, NullCodec::new); + return (Codec)getOrCreateCodec(client.getProtocolProvider(), NULL_CODEC_ID, NullCodec::new); } var reader = new PacketReader(buffer); - return buildCodec(id, reader, cls); + return buildCodec(client, id, reader, cls); } @SuppressWarnings("unchecked") - public static @NotNull Codec buildCodec(@NotNull UUID id, @NotNull PacketReader reader, Class ignoredCodecResult) throws EdgeDBException { - return (Codec) buildCodec(id, reader); + public static @NotNull Codec buildCodec(EdgeDBBinaryClient client, @NotNull UUID id, @NotNull PacketReader reader, Class ignoredCodecResult) throws EdgeDBException { + return (Codec) buildCodec(client, id, reader); } - @SuppressWarnings("unchecked") + public static @NotNull Codec buildCodec(EdgeDBBinaryClient client, @NotNull UUID id, @NotNull PacketReader reader) throws EdgeDBException { try { if(id.equals(NULL_CODEC_ID)) { - return getOrCreateCodec(id, NullCodec::new); + return getOrCreateCodec(client.getProtocolProvider(), id, NullCodec::new); } - var descriptors = new ArrayList>(); + var providerCache = codecCaches.computeIfAbsent(client.getProtocolProvider().getVersion(), CodecCache::new); + + var descriptors = new ArrayList>>(); while(!reader.isEmpty()) { var start = reader.position(); @@ -94,75 +114,78 @@ public final class CodecBuilder { var codecs = new ArrayList>(); for(var i = 0; i != descriptors.size(); i++) { + var descriptor = descriptors.get(i); + + Codec codec = providerCache.cache.get(descriptor.getId());; + + if(codec != null) { + codecs.add(i, codec); + continue; + } + codec = getScalarCodec(client.getProtocolProvider(), descriptor.getId()); + + if(codec != null) { + codecs.add(i, codec); + continue; + } + + codec = client.getProtocolProvider().buildCodec( + descriptor, + codecs::get, + descriptors::get + ); + + codecs.add(i, codec); + + logger.debug("Codec {} added: {}", i, codec); } - //List> codecs = new ArrayList<>(); -// -// while(!reader.isEmpty()) { -// var start = reader.position(); -// var descriptor = TypeDescriptorBuilder.getDescriptor(reader); -// var end = reader.position(); -// -// logger.trace("{}/{}: read {}, size {}", end, reader.size(), descriptor.type, end-start); -// -// Codec codec; -// -// if(codecCache.containsKey(descriptor.getId())) { -// codec = codecCache.get(descriptor.getId()); -// } else { -// codec = getScalarCodec(descriptor.getId()); -// } -// -// if(codec != null) { -// codecs.add(codec); -// continue; -// } -// -// switch (descriptor.type) { -// -// } -// -// codecs.add(codec); -// } -// -// var finalCodec = CollectionUtils.last(codecs); -// -// codecCache.putIfAbsent(id, finalCodec); -// -// return finalCodec; + Codec finalCodec = null; + + for(var i = 1; i != codecs.size() + 1 && finalCodec == null; i++) { + finalCodec = codecs.get(codecs.size() - i); + } + + if(finalCodec == null) { + throw new MissingCodecException("Failed to find end tail of codec tree"); + } + + return finalCodec; } catch (Throwable x) { logger.error("Failed to build codec", x); throw x; } - } public static @NotNull Long getCacheKey(@NotNull String query, @NotNull Cardinality cardinality, @NotNull IOFormat format) { return calculateKnuthHash(query) + cardinality.getValue() + format.getValue(); } - public static @Nullable QueryCodecs getCachedCodecs(long cacheKey) { - var ids = queryCodecCache.get(cacheKey); + public static @Nullable QueryCodecs getCachedCodecs(ProtocolProvider provider, long cacheKey) { + var providerCache = codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new); + + var ids = providerCache.queryCodecsCache.get(cacheKey); if(ids == null) { return null; } - var inCodec = codecCache.get(ids.inputCodecId); - var outCodec = codecCache.get(ids.outputCodecId); + var inCodec = providerCache.cache.get(ids.inputCodecId); + var outCodec = providerCache.cache.get(ids.outputCodecId); if(inCodec == null || outCodec == null) { - queryCodecCache.remove(cacheKey); + providerCache.queryCodecsCache.remove(cacheKey); return null; } return new QueryCodecs(ids.inputCodecId, inCodec, ids.outputCodecId, outCodec); } - public static void updateCachedCodecs(long cacheKey, UUID inCodecId, UUID outCodecId) { - queryCodecCache.computeIfAbsent(cacheKey, (c) -> new QueryCodecCacheEntry(inCodecId, outCodecId)); + public static void updateCachedCodecs(ProtocolProvider provider, long cacheKey, UUID inCodecId, UUID outCodecId) { + codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) + .queryCodecsCache.computeIfAbsent(cacheKey, (c) -> new QueryCodecCacheEntry(inCodecId, outCodecId)); } private static @NotNull Long calculateKnuthHash(@NotNull String str) { @@ -177,16 +200,19 @@ public static void updateCachedCodecs(long cacheKey, UUID inCodecId, UUID outCod } @SuppressWarnings("unchecked") - public static Codec getOrCreateCodec(UUID id, @NotNull Supplier> constructor) { - return (Codec) codecPartsInstanceCache.computeIfAbsent(id, v -> constructor.get()); + public static Codec getOrCreateCodec(ProtocolProvider provider, UUID id, @NotNull Supplier> constructor) { + return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) + .codecPartsInstanceCache.computeIfAbsent(id, v -> constructor.get()); } @SuppressWarnings("unchecked") - private static @Nullable Codec getScalarCodec(UUID id) { - return (Codec) codecPartsInstanceCache.computeIfAbsent(id, - (v) -> scalarCodecFactories.containsKey(v) - ? scalarCodecFactories.get(v).get() - : null + private static @Nullable Codec getScalarCodec(ProtocolProvider provider, UUID id) { + return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) + .codecPartsInstanceCache.computeIfAbsent( + id, + (v) -> scalarCodecFactories.containsKey(v) + ? scalarCodecFactories.get(v).get() + : null ); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java index 92f203f0..b48fe1af 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java @@ -4,7 +4,6 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.protocol.v1.V1ProtocolProvider; -import com.edgedb.driver.binary.protocol.v1.descriptors.TypeDescriptor; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.MissingCodecException; import com.edgedb.driver.exceptions.UnexpectedMessageException; @@ -45,7 +44,7 @@ static void updateProviderFor(EdgeDBBinaryClient client, ProtocolProvider provid TypeDescriptorInfo> readDescriptor(PacketReader reader) throws UnexpectedMessageException; > @Nullable Codec buildCodec( TypeDescriptorInfo descriptor, - Function> getRelativeCodec, Function getRelativeDescriptor + Function> getRelativeCodec, Function> getRelativeDescriptor ) throws MissingCodecException; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java index 6d3de0a7..422baa98 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java @@ -3,6 +3,7 @@ import org.joou.UShort; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -64,4 +65,9 @@ public boolean equals(Object obj) { return this.major == other.major && this.minor == other.minor; } + + @Override + public int hashCode() { + return Objects.hash(major, minor); + } } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java index 112c027d..47aebe38 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java @@ -132,7 +132,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th @Override public > @Nullable Codec buildCodec( TypeDescriptorInfo descriptor, Function> getRelativeCodec, - Function getRelativeDescriptor + Function> getRelativeDescriptor ) throws MissingCodecException { if(!(descriptor.type instanceof DescriptorType)) { throw new IllegalArgumentException("Expected v1 descriptor type, got " + descriptor.type.getClass().getName()); @@ -142,7 +142,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th case ARRAY_TYPE_DESCRIPTOR: var arrayType = descriptor.as(ArrayTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new CompilableCodec( getRelativeCodec.apply(arrayType.typePosition.intValue()), ArrayCodec::new, @@ -154,7 +154,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th // should be resolved by the above case, getting here is an error throw new MissingCodecException(String.format("Could not find the scalar type %s", descriptor.getId().toString())); case ENUMERATION_TYPE_DESCRIPTOR: - return CodecBuilder.getOrCreateCodec(descriptor.getId(), TextCodec::new); + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), TextCodec::new); case INPUT_SHAPE_DESCRIPTOR: var inputShape = descriptor.as(InputShapeDescriptor.class); var inputShapeCodecs = new Codec[inputShape.shapes.length]; @@ -165,7 +165,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th inputShapeNames[i] = inputShape.shapes[i].name; } - return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> new SparseObjectCodec(inputShapeCodecs, inputShapeNames)); + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new SparseObjectCodec(inputShapeCodecs, inputShapeNames)); case TUPLE_TYPE_DESCRIPTOR: var tupleType = descriptor.as(TupleTypeDescriptor.class); var innerCodecs = new Codec[tupleType.elementTypeDescriptorPositions.length]; @@ -174,17 +174,17 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th innerCodecs[i] = getRelativeCodec.apply(tupleType.elementTypeDescriptorPositions[i].intValue()); } - return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> new TupleCodec(innerCodecs)); + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new TupleCodec(innerCodecs)); case NAMED_TUPLE_DESCRIPTOR: var tupleShape = descriptor.as(NamedTupleTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, tupleShape.elements)); + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, tupleShape.elements)); case OBJECT_SHAPE_DESCRIPTOR: var objectShape = descriptor.as(ObjectShapeDescriptor.class); - return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, objectShape.shapes)); + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, objectShape.shapes)); case RANGE_TYPE_DESCRIPTOR: var rangeType = descriptor.as(RangeTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new CompilableCodec( getRelativeCodec.apply(rangeType.typePosition.intValue()), RangeCodec::new, @@ -196,7 +196,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th case SET_DESCRIPTOR: var setTypes = descriptor.as(SetTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(descriptor.getId(), () -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new CompilableCodec( getRelativeCodec.apply(setTypes.typePosition.intValue()), SetCodec::new, @@ -239,7 +239,7 @@ public ProtocolState(QueryParameters args, ByteBuf stateBuffer, List da public CompletionStage parseQuery(QueryParameters queryParameters) { var cacheKey = queryParameters.getCacheKey(); - var cachedCodecs = CodecBuilder.getCachedCodecs(cacheKey); + var cachedCodecs = CodecBuilder.getCachedCodecs(this, cacheKey); ByteBuf stateBuffer; @@ -338,11 +338,13 @@ private CompletionStage parse0(@NotNull QueryParameters args, ProtocolStat state.codecs = new CodecBuilder.QueryCodecs( commandDescriptor.inputTypeDescriptorId, CodecBuilder.buildCodec( + client, commandDescriptor.inputTypeDescriptorId, commandDescriptor.inputTypeDescriptorBuffer ), commandDescriptor.outputTypeDescriptorId, CodecBuilder.buildCodec( + client, commandDescriptor.outputTypeDescriptorId, commandDescriptor.outputTypeDescriptorBuffer ) @@ -356,6 +358,7 @@ private CompletionStage parse0(@NotNull QueryParameters args, ProtocolStat ); CodecBuilder.updateCachedCodecs( + this, args.getCacheKey(), commandDescriptor.inputTypeDescriptorId, commandDescriptor.outputTypeDescriptorId @@ -367,6 +370,7 @@ private CompletionStage parse0(@NotNull QueryParameters args, ProtocolStat case READY_FOR_COMMAND: var ready = result.packet.as(ReadyForCommand.class); client.setTransactionState(ready.transactionState); + state.isComplete = state.codecs != null; result.finishDuplexing(); } @@ -410,11 +414,11 @@ private CompletionStage execute0(QueryParameters queryParameters, ParseRes try { return client.getDuplexer().duplexAndSync(new Execute( - parseResult.capabilities, + queryParameters.capabilities, getCompilationFlags(queryParameters), client.getConfig().getImplicitLimit(), queryParameters.format, - parseResult.cardinality, + queryParameters.cardinality, queryParameters.query, client.getStateDescriptorId(), parseResult.stateData, @@ -477,6 +481,8 @@ private CompletionStage execute0(QueryParameters queryParameters, ParseRes } private void handleCommandError(@NotNull QueryParameters queryParameters, @NotNull V1ProtocolProvider.ProtocolState args, Duplexer.@NotNull DuplexResult result, @NotNull ErrorResponse err) { + logger.debug("Processing command phase error {}", err.errorCode); + if(err.errorCode == ErrorCode.STATE_MISMATCH_ERROR) { logger.debug("Has updated state?: {}", args.stateUpdated); // should have new state @@ -494,11 +500,12 @@ private void handleCommandError(@NotNull QueryParameters queryParameters, @NotNu private void updateStateCodec(ProtocolState state, Duplexer.@NotNull DuplexResult result) { var stateDescriptor = result.packet.as(StateDataDescription.class); - var codec = CodecBuilder.getCodec(stateDescriptor.typeDescriptorId, Map.class); + var codec = CodecBuilder.getCodec(this, stateDescriptor.typeDescriptorId, Map.class); if(codec == null) { try { codec = CodecBuilder.buildCodec( + client, stateDescriptor.typeDescriptorId, stateDescriptor.typeDescriptorBuffer, Map.class @@ -510,9 +517,14 @@ private void updateStateCodec(ProtocolState state, Duplexer.@NotNull DuplexResul client.setStateCodec(codec); client.setStateDescriptorId(stateDescriptor.typeDescriptorId); + state.stateUpdated = true; try { + if(state.stateBuffer != null) { + state.stateBuffer.release(); + } + state.stateBuffer = client.serializeState(); } catch (OperationNotSupportedException | EdgeDBException e) { result.finishExceptionally("Failed to serialize state", e, EdgeDBException::new); @@ -651,13 +663,13 @@ public CompletionStage processMessage(Receivable packet) { case STATE_DATA_DESCRIPTION: var stateDescriptor = (StateDataDescription)packet; - var codec = CodecBuilder.getCodec(stateDescriptor.typeDescriptorId, Map.class); + var codec = CodecBuilder.getCodec(this, stateDescriptor.typeDescriptorId, Map.class); if(codec == null) { assert stateDescriptor.typeDescriptorBuffer != null; var reader = new PacketReader(stateDescriptor.typeDescriptorBuffer); - codec = CodecBuilder.buildCodec(stateDescriptor.typeDescriptorId, reader, Map.class); + codec = CodecBuilder.buildCodec(client, stateDescriptor.typeDescriptorId, reader, Map.class); } client.setStateDescriptorId(stateDescriptor.typeDescriptorId); @@ -682,6 +694,9 @@ public CompletionStage processMessage(Receivable packet) { break; } break; + case READY_FOR_COMMAND: + this.phase = ProtocolPhase.COMMAND; + break; } } catch (Exception x) { @@ -716,11 +731,11 @@ private void parseServerSettings(@NotNull ParameterStatus status) throws EdgeDBE var descriptorLength = reader.readInt32() - 16; var descriptorId = reader.readUUID(); - var codec = CodecBuilder.getCodec(descriptorId, Map.class); + var codec = CodecBuilder.getCodec(this, descriptorId, Map.class); if(codec == null) { var descriptorReader = new PacketReader(reader.readBytes(descriptorLength)); - codec = CodecBuilder.buildCodec(descriptorId, descriptorReader, Map.class); + codec = CodecBuilder.buildCodec(client, descriptorId, descriptorReader, Map.class); } reader.skip(BinaryProtocolUtils.INT_SIZE); // discard length @@ -781,7 +796,6 @@ private CompletionStage startSASLAuthentication(@NotNull AuthenticationSta case AUTHENTICATION_OK: logger.debug("Completing auth duplex"); state.finishDuplexing(); - this.phase = ProtocolPhase.COMMAND; break; default: throw new UnexpectedMessageException( diff --git a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java index 2146c8f0..c107f514 100644 --- a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java +++ b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java @@ -39,7 +39,7 @@ public abstract class EdgeDBBinaryClient extends BaseEdgeDBClient { private UUID stateDescriptorId; private @Nullable Long suggestedPoolConcurrency; - private ProtocolProvider protocolProvider; + private @NotNull ProtocolProvider protocolProvider; private short connectionAttempts; private final @NotNull Semaphore connectionSemaphore; private final @NotNull Semaphore querySemaphore; @@ -52,11 +52,12 @@ public EdgeDBBinaryClient(EdgeDBConnection connection, EdgeDBClientConfig config this.querySemaphore = new Semaphore(1); this.readyPromise = new CompletableFuture<>(); this.stateDescriptorId = CodecBuilder.INVALID_CODEC_ID; + this.protocolProvider = ProtocolProvider.getProvider(this); } public abstract Duplexer getDuplexer(); - public ProtocolProvider getProtocolProvider() { + public @NotNull ProtocolProvider getProtocolProvider() { return this.protocolProvider; } @@ -445,12 +446,15 @@ private CompletionStage doClientHandshake() { .readNext() .thenCompose(protocolProvider::processMessage) .thenCompose(v -> { + logger.debug("Protocol phase: {}", protocolProvider.getPhase()); + if(protocolProvider.getPhase() != ProtocolPhase.COMMAND) { logger.debug("Rerunning handshake, phase: {}", protocolProvider.getPhase()); return doClientHandshake(); } - return CompletableFuture.completedFuture((Void)null); + this.readyPromise.complete(null); + return dispatchReady(); }), error -> { if(error instanceof EdgeDBErrorException && ((EdgeDBException)error).shouldReconnect) { From ffaa6f86d386f2c751a3160c94672c324b180a3a Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Thu, 27 Jul 2023 15:25:25 -0300 Subject: [PATCH 03/10] make other binding code protocol-agnostic --- .../builders/TypeDescriptorBuilder.java | 59 ------- .../driver/binary/codecs/ObjectCodec.java | 35 ---- .../binary/duplexers/ChannelDuplexer.java | 3 +- .../{v1/descriptors => }/TypeDescriptor.java | 2 +- .../binary/protocol/TypeDescriptorInfo.java | 2 - .../protocol/v1/V1ProtocolProvider.java | 162 +++++++++++------- .../v1/descriptors/ArrayTypeDescriptor.java | 1 + .../descriptors/BaseScalarTypeDescriptor.java | 1 + .../EnumerationTypeDescriptor.java | 1 + .../v1/descriptors/InputShapeDescriptor.java | 1 + .../descriptors/NamedTupleTypeDescriptor.java | 1 + .../v1/descriptors/ObjectShapeDescriptor.java | 1 + .../v1/descriptors/RangeTypeDescriptor.java | 1 + .../v1/descriptors/ScalarTypeDescriptor.java | 1 + .../descriptors/ScalarTypeNameAnnotation.java | 1 + .../v1/descriptors/SetTypeDescriptor.java | 1 + .../v1/descriptors/TupleTypeDescriptor.java | 1 + .../descriptors/TypeAnnotationDescriptor.java | 1 + .../edgedb/driver/util/ComposableUtil.java | 18 ++ .../java/com/edgedb/driver/util/Scram.java | 26 +-- 20 files changed, 140 insertions(+), 179 deletions(-) delete mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java rename src/driver/src/main/java/com/edgedb/driver/binary/protocol/{v1/descriptors => }/TypeDescriptor.java (57%) diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java deleted file mode 100644 index 1ed0287d..00000000 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/TypeDescriptorBuilder.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.edgedb.driver.binary.builders; - -import com.edgedb.driver.binary.PacketReader; -import com.edgedb.driver.binary.protocol.v1.descriptors.*; -import com.edgedb.driver.exceptions.EdgeDBException; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.function.BiFunction; - -import static org.joou.Unsigned.ubyte; - -public final class TypeDescriptorBuilder { - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - private static final @NotNull Map> typeDescriptorFactories; - - static { - typeDescriptorFactories = new HashMap<>() { - { - - } - }; - } - - public static @NotNull TypeDescriptorResult getDescriptor(final @NotNull PacketReader reader) throws EdgeDBException { - var type = reader.readEnum(DescriptorType.class, Byte.TYPE); - var id = reader.readUUID(); - - var factory = typeDescriptorFactories.get(type); - - if(factory != null) { - return new TypeDescriptorResult(type, factory.apply(id, reader)); - } - - var v = ubyte(type.getValue()); - - if (v.compareTo(ubyte(0x80)) >= 0 && v.compareTo(ubyte(0xfe)) <= 0) { - return new TypeDescriptorResult(type, new TypeAnnotationDescriptor(type, id, reader)); - } - - throw new EdgeDBException(String.format("No descriptor found for type %X", v.byteValue())); - } - - public static class TypeDescriptorResult { - public final DescriptorType type; - private final TypeDescriptor descriptor; - - public TypeDescriptorResult(DescriptorType type, TypeDescriptor descriptor) { - this.type = type; - this.descriptor = descriptor; - } - - public UUID getId() { - return descriptor.getId(); - } - } -} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java index 761209a9..0cc4d724 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java @@ -5,8 +5,6 @@ import com.edgedb.driver.binary.builders.internal.ObjectEnumeratorImpl; import com.edgedb.driver.binary.builders.types.TypeBuilder; import com.edgedb.driver.binary.builders.types.TypeDeserializerInfo; -import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; -import com.edgedb.driver.binary.protocol.v1.descriptors.common.TupleElement; import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.exceptions.NoTypeConverterException; @@ -17,7 +15,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; @SuppressWarnings("rawtypes") public class ObjectCodec extends CodecBase implements ArgumentCodec { @@ -96,38 +93,6 @@ public ObjectCodec(ObjectProperty... elements) { this.typeCodecs = new ConcurrentHashMap<>(); } - public static @NotNull ObjectCodec create(@NotNull Function> fetchCodec, ShapeElement @NotNull [] shape) { - var elements = new ObjectProperty[shape.length]; - - for (int i = 0; i < shape.length; i++) { - var shapeElement = shape[i]; - - elements[i] = new ObjectProperty( - shapeElement.name, - fetchCodec.apply(shapeElement.typePosition.intValue()), - shapeElement.cardinality - ); - } - - return new ObjectCodec(elements); - } - - public static @NotNull ObjectCodec create(@NotNull Function> fetchCodec, TupleElement @NotNull [] shape) { - var elements = new ObjectProperty[shape.length]; - - for (int i = 0; i < shape.length; i++) { - var shapeElement = shape[i]; - - elements[i] = new ObjectProperty( - shapeElement.name, - fetchCodec.apply((int)shapeElement.typePosition), - null - ); - } - - return new ObjectCodec(elements); - } - public TypeInitializedObjectCodec getOrCreateTypeCodec(Class cls) throws EdgeDBException { return getOrCreateTypeCodec(cls, t -> new TypeInitializedObjectCodec(t, this)); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java index d88f83fa..a7842d35 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java @@ -4,7 +4,6 @@ import com.edgedb.driver.binary.protocol.ProtocolProvider; import com.edgedb.driver.binary.protocol.Receivable; import com.edgedb.driver.binary.protocol.Sendable; -import com.edgedb.driver.binary.protocol.v1.sendables.Terminate; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.ConnectionFailedException; import com.edgedb.driver.exceptions.ConnectionFailedTemporarilyException; @@ -328,7 +327,7 @@ public CompletionStage disconnect() { } if(this.channel.isOpen()) { - return send(new Terminate()) + return send(getProtocolProvider().terminate()) .thenCompose(v -> ChannelCompletableFuture.completeFrom(this.channel.disconnect())); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptor.java similarity index 57% rename from src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptor.java index 1c8c8460..c0ee4c7c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptor.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.protocol.v1.descriptors; +package com.edgedb.driver.binary.protocol; import java.util.UUID; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java index c718aeac..6b70b860 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/TypeDescriptorInfo.java @@ -1,7 +1,5 @@ package com.edgedb.driver.binary.protocol; -import com.edgedb.driver.binary.protocol.v1.descriptors.TypeDescriptor; - import java.util.UUID; public class TypeDescriptorInfo> { diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java index 47aebe38..b185c7d8 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java @@ -18,6 +18,7 @@ import com.edgedb.driver.util.BinaryProtocolUtils; import com.edgedb.driver.util.Scram; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -35,6 +36,7 @@ import java.util.function.Function; import java.util.function.Predicate; +import static com.edgedb.driver.util.ComposableUtil.composeWith; import static com.edgedb.driver.util.ComposableUtil.exceptionallyCompose; import static org.joou.Unsigned.ushort; @@ -176,11 +178,39 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new TupleCodec(innerCodecs)); case NAMED_TUPLE_DESCRIPTOR: + { var tupleShape = descriptor.as(NamedTupleTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, tupleShape.elements)); + + var elements = new ObjectCodec.ObjectProperty[tupleShape.elements.length]; + + for(var i = 0; i != tupleShape.elements.length; i++) { + var element = tupleShape.elements[i]; + elements[i] = new ObjectCodec.ObjectProperty( + element.name, + getRelativeCodec.apply((int)element.typePosition), + null + ); + } + + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new ObjectCodec(elements)); + } case OBJECT_SHAPE_DESCRIPTOR: + { var objectShape = descriptor.as(ObjectShapeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> ObjectCodec.create(getRelativeCodec, objectShape.shapes)); + + var elements = new ObjectCodec.ObjectProperty[objectShape.shapes.length]; + + for(var i = 0; i != objectShape.shapes.length; i++) { + var element = objectShape.shapes[i]; + elements[i] = new ObjectCodec.ObjectProperty( + element.name, + getRelativeCodec.apply(element.typePosition.intValue()), + element.cardinality + ); + } + + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new ObjectCodec(elements)); + } case RANGE_TYPE_DESCRIPTOR: var rangeType = descriptor.as(RangeTypeDescriptor.class); @@ -762,71 +792,87 @@ private CompletionStage startSASLAuthentication(@NotNull AuthenticationSta } var connection = client.getConnectionArguments(); - var initialMessage = scram.buildInitialMessagePacket(connection.getUsername(), method); + var initialMessage = scram.buildInitialMessage(connection.getUsername()); AtomicReference signature = new AtomicReference<>(new byte[0]); - try{ - return client.getDuplexer().duplex(initialMessage, (state) -> { - logger.debug("Authentication duplex: M:{}", state.packet.getMessageType()); - try { - switch (state.packet.getMessageType()) { - case AUTHENTICATION: - var auth = (AuthenticationStatus)state.packet; - - logger.debug("Processing auth part: {}", auth.authStatus); - - switch (auth.authStatus) { - case AUTHENTICATION_SASL_CONTINUE: - var result = scram.buildFinalMessage(auth, connection.getPassword()); - signature.set(result.signature); - return client.getDuplexer().send(result.buildPacket()); - case AUTHENTICATION_SASL_FINAL: - var key = Scram.parseServerFinalMessage(auth); - - if(!Arrays.equals(signature.get(), key)) { - logger.error( - "The SCRAM signature didn't match. ours: {}, servers: {}.", - signature.get(), - key - ); - throw new InvalidSignatureException(); + + + try { + return composeWith( + Unpooled.wrappedBuffer(initialMessage.getBytes(StandardCharsets.UTF_8)), + buffer -> client.getDuplexer().duplex(new AuthenticationSASLInitialResponse( + buffer, + method + ), (state) -> { + logger.debug("Authentication duplex: M:{}", state.packet.getMessageType()); + try { + switch (state.packet.getMessageType()) { + case AUTHENTICATION: + var auth = (AuthenticationStatus)state.packet; + + logger.debug("Processing auth part: {}", auth.authStatus); + + switch (auth.authStatus) { + case AUTHENTICATION_SASL_CONTINUE: + assert auth.saslData != null; + + var result = scram.buildFinalMessage(Scram.decodeString(auth.saslData), connection.getPassword()); + signature.set(result.signature); + + return composeWith( + Scram.encodeString(result.message), + resultBuffer -> client.getDuplexer().send(new AuthenticationSASLResponse(resultBuffer)) + ); + case AUTHENTICATION_SASL_FINAL: + assert auth.saslData != null; + + var key = Scram.parseServerFinalMessage(auth.saslData); + + if(!Arrays.equals(signature.get(), key)) { + logger.error( + "The SCRAM signature didn't match. ours: {}, servers: {}.", + signature.get(), + key + ); + throw new InvalidSignatureException(); + } + break; + case AUTHENTICATION_OK: + logger.debug("Completing auth duplex"); + state.finishDuplexing(); + break; + default: + throw new UnexpectedMessageException( + "Expected continue or final but got " + auth.authStatus + ); } break; - case AUTHENTICATION_OK: - logger.debug("Completing auth duplex"); - state.finishDuplexing(); - break; + case ERROR_RESPONSE: + throw ((ErrorResponse)state.packet).toException(); default: - throw new UnexpectedMessageException( - "Expected continue or final but got " + auth.authStatus - ); - } - break; - case ERROR_RESPONSE: - throw ((ErrorResponse)state.packet).toException(); - default: - logger.error( - "Unexpected message. expected: {} actual: {}", - ServerMessageType.AUTHENTICATION, - state.packet.getMessageType() - ); - throw new CompletionException( - new UnexpectedMessageException( + logger.error( + "Unexpected message. expected: {} actual: {}", ServerMessageType.AUTHENTICATION, state.packet.getMessageType() - ) - ); - } - } // TODO: should reconnect & should retry exceptions - catch (Exception err) { - this.phase = ProtocolPhase.ERRORED; - state.finishExceptionally(err); - return CompletableFuture.failedFuture(err); - } + ); + throw new CompletionException( + new UnexpectedMessageException( + ServerMessageType.AUTHENTICATION, + state.packet.getMessageType() + ) + ); + } + } // TODO: should reconnect & should retry exceptions + catch (Exception err) { + this.phase = ProtocolPhase.ERRORED; + state.finishExceptionally(err); + return CompletableFuture.failedFuture(err); + } - return CompletableFuture.completedFuture(null); - }); + return CompletableFuture.completedFuture(null); + }) + ); } catch (Throwable x) { return CompletableFuture.failedFuture(x); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ArrayTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ArrayTypeDescriptor.java index 4a47b376..9f1b0ced 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ArrayTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ArrayTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import org.joou.UInteger; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/BaseScalarTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/BaseScalarTypeDescriptor.java index 67fdf1a5..cca03a29 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/BaseScalarTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/BaseScalarTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import java.util.UUID; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/EnumerationTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/EnumerationTypeDescriptor.java index 62e65039..535812e5 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/EnumerationTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/EnumerationTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import java.util.UUID; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java index 7428009b..774fd8e8 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java @@ -1,5 +1,6 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java index 18595936..0f82b1a7 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import com.edgedb.driver.binary.protocol.v1.descriptors.common.TupleElement; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java index 8546a2e9..539c64bf 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java @@ -1,5 +1,6 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/RangeTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/RangeTypeDescriptor.java index db87d1dc..7e081689 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/RangeTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/RangeTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeDescriptor.java index b754556e..8177133b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeNameAnnotation.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeNameAnnotation.java index 902d1240..6ee62b5f 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeNameAnnotation.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ScalarTypeNameAnnotation.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import java.util.UUID; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/SetTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/SetTypeDescriptor.java index e7919f94..50cb0fe4 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/SetTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/SetTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TupleTypeDescriptor.java index 8a78c93d..104051b8 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TupleTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TupleTypeDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeAnnotationDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeAnnotationDescriptor.java index 2dddc4ea..c0cc52e0 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeAnnotationDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/TypeAnnotationDescriptor.java @@ -1,6 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; import org.jetbrains.annotations.NotNull; import java.util.UUID; diff --git a/src/driver/src/main/java/com/edgedb/driver/util/ComposableUtil.java b/src/driver/src/main/java/com/edgedb/driver/util/ComposableUtil.java index 1ac9e184..3c976945 100644 --- a/src/driver/src/main/java/com/edgedb/driver/util/ComposableUtil.java +++ b/src/driver/src/main/java/com/edgedb/driver/util/ComposableUtil.java @@ -1,5 +1,6 @@ package com.edgedb.driver.util; +import io.netty.util.ReferenceCounted; import org.jetbrains.annotations.NotNull; import java.util.concurrent.CompletableFuture; @@ -34,6 +35,23 @@ public static , V extends AutoCloseable> Complet ); } + public static , V extends ReferenceCounted> CompletionStage composeWith( + @NotNull V with, + @NotNull Function composed + ) { + return composed.apply(with) + .thenApply((v) -> { + try { + with.release(); + } catch (Exception x) { + throw new CompletionException(x); + } + + return v; + } + ); + } + public static , V extends AutoCloseable, W extends CompletionStage> CompletionStage composeWith( @NotNull W with, diff --git a/src/driver/src/main/java/com/edgedb/driver/util/Scram.java b/src/driver/src/main/java/com/edgedb/driver/util/Scram.java index 78a059c4..b98328ca 100644 --- a/src/driver/src/main/java/com/edgedb/driver/util/Scram.java +++ b/src/driver/src/main/java/com/edgedb/driver/util/Scram.java @@ -1,8 +1,5 @@ package com.edgedb.driver.util; -import com.edgedb.driver.binary.protocol.v1.receivables.AuthenticationStatus; -import com.edgedb.driver.binary.protocol.v1.sendables.AuthenticationSASLInitialResponse; -import com.edgedb.driver.binary.protocol.v1.sendables.AuthenticationSASLResponse; import com.edgedb.driver.exceptions.ScramException; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; @@ -47,14 +44,14 @@ private static byte[] generateNonce() { return bytes; } - private static @NotNull ByteBuf encodeString(@NotNull String s) { + public static @NotNull ByteBuf encodeString(@NotNull String s) { var buffer = ByteBufAllocator.DEFAULT.buffer(BinaryProtocolUtils.sizeOf(s) - 4); // no str length var encoded = s.getBytes(StandardCharsets.UTF_8); buffer.writeBytes(encoded); return buffer; } - private static @NotNull String decodeString(@NotNull ByteBuf buffer) { + public static @NotNull String decodeString(@NotNull ByteBuf buffer) { byte[] strBytes = new byte[buffer.readableBytes()]; buffer.readBytes(strBytes); @@ -71,11 +68,6 @@ private static byte[] generateNonce() { return "n,," + this.rawFirstMessage; } - public @NotNull AuthenticationSASLInitialResponse buildInitialMessagePacket(@NotNull String username, String method) { - var initial = buildInitialMessage(username); - return new AuthenticationSASLInitialResponse(encodeString(initial), method); - } - public static class SASLFinalMessage { public final String message; public final byte[] signature; @@ -84,15 +76,6 @@ public SASLFinalMessage(String message, byte[] signature) { this.message = message; this.signature = signature; } - - public @NotNull AuthenticationSASLResponse buildPacket() { - return new AuthenticationSASLResponse(encodeString(this.message)); - } - } - - public @NotNull SASLFinalMessage buildFinalMessage(@NotNull AuthenticationStatus status, @NotNull String password) throws ScramException { - assert status.saslData != null; - return buildFinalMessage(decodeString(status.saslData), password); } public @NotNull SASLFinalMessage buildFinalMessage(@NotNull String initialResponse, @NotNull String password) throws ScramException { @@ -131,9 +114,8 @@ public SASLFinalMessage(String message, byte[] signature) { ); } - public static byte[] parseServerFinalMessage(@NotNull AuthenticationStatus status) { - assert status.saslData != null; - var message = decodeString(status.saslData); + public static byte[] parseServerFinalMessage(@NotNull ByteBuf status) { + var message = decodeString(status); var parsed = parseServerMessage(message); From 4a122fa779a0c630dbba6424f72186007c518644 Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Thu, 27 Jul 2023 17:49:47 -0300 Subject: [PATCH 04/10] v2 protocol partial implementation --- .../driver/binary/builders/CodecBuilder.java | 11 +- .../driver/binary/codecs/ArrayCodec.java | 5 +- .../edgedb/driver/binary/codecs/Codec.java | 3 + .../driver/binary/codecs/CodecBase.java | 10 +- .../driver/binary/codecs/CompilableCodec.java | 21 +++- .../driver/binary/codecs/CompoundCodec.java | 32 +++++ .../driver/binary/codecs/NullCodec.java | 7 ++ .../driver/binary/codecs/ObjectCodec.java | 9 +- .../driver/binary/codecs/RangeCodec.java | 5 +- .../edgedb/driver/binary/codecs/SetCodec.java | 5 +- .../binary/codecs/SparseObjectCodec.java | 5 +- .../driver/binary/codecs/TupleCodec.java | 6 +- .../codecs/complex/ComplexCodecBase.java | 10 +- .../binary/codecs/scalars/BigIntCodec.java | 4 +- .../binary/codecs/scalars/BoolCodec.java | 4 +- .../scalars/{complex => }/BytesCodec.java | 7 +- .../codecs/scalars/DateDurationCodec.java | 4 +- .../binary/codecs/scalars/DecimalCodec.java | 4 +- .../binary/codecs/scalars/DurationCodec.java | 4 +- .../binary/codecs/scalars/Float32Codec.java | 4 +- .../binary/codecs/scalars/Float64Codec.java | 4 +- .../binary/codecs/scalars/Integer16Codec.java | 4 +- .../binary/codecs/scalars/Integer32Codec.java | 5 +- .../binary/codecs/scalars/Integer64Codec.java | 6 +- .../binary/codecs/scalars/JsonCodec.java | 4 +- .../binary/codecs/scalars/LocalDateCodec.java | 4 +- .../codecs/scalars/LocalDateTimeCodec.java | 5 +- .../binary/codecs/scalars/LocalTimeCodec.java | 5 +- .../binary/codecs/scalars/MemoryCodec.java | 5 +- .../codecs/scalars/ScalarCodecBase.java | 6 +- .../binary/codecs/scalars/TextCodec.java | 5 +- .../binary/codecs/scalars/UUIDCodec.java | 3 +- .../complex/ComplexScalarCodecBase.java | 7 +- .../codecs/scalars/complex/DateTimeCodec.java | 6 +- .../complex/RelativeDurationCodec.java | 4 + .../common/descriptors/CodecAncestor.java | 14 +++ .../common/descriptors/CodecMetadata.java | 19 +++ .../descriptors}/ShapeElement.java | 3 +- .../descriptors}/ShapeElementFlags.java | 2 +- .../descriptors}/TupleElement.java | 2 +- .../common/descriptors/TypeOperation.java | 19 +++ .../protocol/v1/V1ProtocolProvider.java | 35 ++++-- .../v1/descriptors/InputShapeDescriptor.java | 2 +- .../descriptors/NamedTupleTypeDescriptor.java | 2 +- .../v1/descriptors/ObjectShapeDescriptor.java | 2 +- .../protocol/v2/V2ProtocolProvider.java | 109 ++++++++++++++++++ .../v2/descriptors/ArrayTypeDescriptor.java | 47 ++++++++ .../descriptors/CompoundTypeDescriptor.java | 42 +++++++ .../v2/descriptors/DescriptorType.java | 29 +++++ .../EnumerationTypeDescriptor.java | 45 ++++++++ .../v2/descriptors/InputShapeDescriptor.java | 23 ++++ .../v2/descriptors/MetadataDescriptor.java | 34 ++++++ .../descriptors/NamedTupleTypeDescriptor.java | 46 ++++++++ .../ObjectOutputShapeDescriptor.java | 26 +++++ .../v2/descriptors/ObjectTypeDescriptor.java | 39 +++++++ .../v2/descriptors/RangeTypeDescriptor.java | 45 ++++++++ .../v2/descriptors/ScalarTypeDescriptor.java | 43 +++++++ .../v2/descriptors/SetDescriptor.java | 22 ++++ .../protocol/v2/descriptors/ShapeElement.java | 23 ++++ .../v2/descriptors/TupleTypeDescriptor.java | 45 ++++++++ .../TypeAnnotationTextDescriptor.java | 27 +++++ 61 files changed, 911 insertions(+), 67 deletions(-) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java rename src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/{complex => }/BytesCodec.java (87%) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecAncestor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java rename src/driver/src/main/java/com/edgedb/driver/binary/protocol/{v1/descriptors/common => common/descriptors}/ShapeElement.java (84%) rename src/driver/src/main/java/com/edgedb/driver/binary/protocol/{v1/descriptors/common => common/descriptors}/ShapeElementFlags.java (88%) rename src/driver/src/main/java/com/edgedb/driver/binary/protocol/{v1/descriptors/common => common/descriptors}/TupleElement.java (84%) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/TypeOperation.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ArrayTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/EnumerationTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/InputShapeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/MetadataDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectOutputShapeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/RangeTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ScalarTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TupleTypeDescriptor.java create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TypeAnnotationTextDescriptor.java diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java index bc2b6df9..88a33004 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java @@ -4,7 +4,7 @@ import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.codecs.NullCodec; import com.edgedb.driver.binary.codecs.scalars.*; -import com.edgedb.driver.binary.codecs.scalars.complex.BytesCodec; +import com.edgedb.driver.binary.codecs.scalars.BytesCodec; import com.edgedb.driver.binary.codecs.scalars.complex.DateTimeCodec; import com.edgedb.driver.binary.codecs.scalars.complex.RelativeDurationCodec; import com.edgedb.driver.binary.protocol.ProtocolProvider; @@ -28,6 +28,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; import java.util.function.Supplier; public final class CodecBuilder { @@ -202,7 +203,13 @@ public static void updateCachedCodecs(ProtocolProvider provider, long cacheKey, @SuppressWarnings("unchecked") public static Codec getOrCreateCodec(ProtocolProvider provider, UUID id, @NotNull Supplier> constructor) { return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) - .codecPartsInstanceCache.computeIfAbsent(id, v -> constructor.get()); + .codecPartsInstanceCache.computeIfAbsent(id, ignored -> constructor.get()); + } + + @SuppressWarnings("unchecked") + public static Codec getOrCreateCodec(ProtocolProvider provider, UUID id, @NotNull Function> constructor) { + return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) + .codecPartsInstanceCache.computeIfAbsent(id, constructor); } @SuppressWarnings("unchecked") diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java index f9a6e394..38e5a562 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java @@ -9,6 +9,7 @@ import javax.naming.OperationNotSupportedException; import java.lang.reflect.Array; +import java.util.UUID; public class ArrayCodec extends CodecBase { private static final byte[] EMPTY_ARRAY = new byte[] { @@ -22,8 +23,8 @@ public class ArrayCodec extends CodecBase { private final Codec innerCodec; @SuppressWarnings("unchecked") - public ArrayCodec(Class cls, Codec codec) { - super((Class) cls); + public ArrayCodec(UUID id, Class cls, Codec codec) { + super(id, (Class) cls); this.innerCodec = (Codec) codec; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java index ce8b24af..60bbc0af 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java @@ -9,8 +9,11 @@ import javax.naming.OperationNotSupportedException; import java.lang.reflect.Type; +import java.util.UUID; public interface Codec { + UUID getId(); + void serialize(final PacketWriter writer, final @Nullable T value, final CodecContext context) throws OperationNotSupportedException, EdgeDBException; @Nullable T deserialize(final PacketReader reader, final CodecContext context) throws EdgeDBException, OperationNotSupportedException; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java index b0f1f5d5..77f1602d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java @@ -3,12 +3,20 @@ import org.jetbrains.annotations.NotNull; import java.lang.reflect.Type; +import java.util.UUID; public abstract class CodecBase implements Codec { + public final UUID id; private final Class cls; - public CodecBase(Class cls) { + public CodecBase(UUID id, Class cls) { this.cls = cls; + this.id = id; + } + + @Override + public UUID getId() { + return this.id; } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java index a6c012ac..d3ef04bd 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java @@ -7,25 +7,33 @@ import javax.naming.OperationNotSupportedException; import java.lang.reflect.Type; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.function.BiFunction; import java.util.function.Function; @SuppressWarnings("rawtypes") public final class CompilableCodec implements Codec { + @FunctionalInterface + public interface CompilableFactory { + Codec compile(UUID id, Class cls, Codec innerCodec); + } + private final Codec innerCodec; - private final BiFunction, Codec, Codec> factory; + private final CompilableFactory factory; private final @NotNull ConcurrentMap, Codec> instanceCache; private final Function, Class> compilableTypeFactory; + private final UUID id; private @Nullable Class compilableType; public CompilableCodec( + UUID id, Codec innerCodec, - BiFunction, Codec, Codec> factory, + CompilableFactory factory, Function, Class> compilableTypeFactory ) { + this.id = id; this.factory = factory; this.innerCodec = innerCodec; this.instanceCache = new ConcurrentHashMap<>(); @@ -45,7 +53,7 @@ public Codec getInnerCodec() { } public Codec compile(Class cls, Codec innerCodec) { - return instanceCache.computeIfAbsent(cls, (c) -> this.factory.apply(c, innerCodec)); + return instanceCache.computeIfAbsent(cls, (c) -> this.factory.compile(this.id, c, innerCodec)); } public Class getInnerType() { @@ -54,6 +62,11 @@ public Class getInnerType() { : this.innerCodec.getConvertingClass(); } + @Override + public UUID getId() { + return this.id; + } + @Override public void serialize(PacketWriter writer, @Nullable Object value, CodecContext context) throws OperationNotSupportedException { throw new OperationNotSupportedException(); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java new file mode 100644 index 00000000..20d9c6ed --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java @@ -0,0 +1,32 @@ +package com.edgedb.driver.binary.codecs; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.protocol.common.descriptors.TypeOperation; +import com.edgedb.driver.exceptions.EdgeDBException; +import org.jetbrains.annotations.Nullable; + +import javax.naming.OperationNotSupportedException; +import java.util.UUID; + +public class CompoundCodec extends CodecBase { + + public CompoundCodec( + UUID id, + Class cls, + TypeOperation operation, + ) { + super(id, cls); + } + + @Override + public void serialize(PacketWriter writer, @Nullable Object value, CodecContext context) throws OperationNotSupportedException, EdgeDBException { + + } + + @Nullable + @Override + public Object deserialize(PacketReader reader, CodecContext context) throws EdgeDBException, OperationNotSupportedException { + return null; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java index feb7a4dc..619abc85 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java @@ -2,14 +2,21 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.builders.CodecBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; import java.lang.reflect.Type; import java.util.Map; +import java.util.UUID; public final class NullCodec implements Codec, ArgumentCodec { + @Override + public UUID getId() { + return CodecBuilder.NULL_CODEC_ID; + } + @Override public void serialize(@NotNull PacketWriter writer, @Nullable Void value, CodecContext context) throws OperationNotSupportedException { writer.write(0); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java index 0cc4d724..10c3f1e3 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java @@ -13,6 +13,7 @@ import javax.naming.OperationNotSupportedException; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -28,7 +29,7 @@ public static final class TypeInitializedObjectCodec extends ObjectCodec { private final @NotNull ObjectCodec parent; public TypeInitializedObjectCodec(@NotNull Class target, @NotNull ObjectCodec parent) throws EdgeDBException { - super(parent.elements); + super(parent.id, parent.elements); this.parent = parent; this.target = target; @@ -40,7 +41,7 @@ public TypeInitializedObjectCodec(@NotNull Class target, @NotNull ObjectCodec } public TypeInitializedObjectCodec(@NotNull TypeDeserializerInfo info, @NotNull ObjectCodec parent) { - super(parent.elements); + super(parent.id, parent.elements); this.parent = parent; this.target = info.getType(); @@ -87,8 +88,8 @@ public ObjectProperty(String name, Codec codec, @Nullable Cardinality cardina public final ObjectProperty[] elements; private final @NotNull ConcurrentMap, TypeInitializedObjectCodec> typeCodecs; - public ObjectCodec(ObjectProperty... elements) { - super(Object.class); + public ObjectCodec(UUID id, ObjectProperty... elements) { + super(id, Object.class); this.elements = elements; this.typeCodecs = new ConcurrentHashMap<>(); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java index 3a0360d6..f17477dc 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java @@ -12,13 +12,14 @@ import javax.naming.OperationNotSupportedException; import java.util.EnumSet; +import java.util.UUID; public final class RangeCodec extends CodecBase> { private final Codec innerCodec; @SuppressWarnings("unchecked") - public RangeCodec(Class cls, Codec innerCodec) { - super((Class>) cls); + public RangeCodec(UUID id, Class cls, Codec innerCodec) { + super(id, (Class>) cls); this.innerCodec = (Codec) innerCodec; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java index 64752e44..a0f083c1 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Set; +import java.util.UUID; import static com.edgedb.driver.util.BinaryProtocolUtils.INT_SIZE; import static com.edgedb.driver.util.BinaryProtocolUtils.LONG_SIZE; @@ -19,8 +20,8 @@ public final class SetCodec extends CodecBase> { private final Codec innerCodec; @SuppressWarnings("unchecked") - public SetCodec(Class cls, Codec innerCodec) { - super((Class>) cls); + public SetCodec(UUID id, Class cls, Codec innerCodec) { + super(id, (Class>) cls); this.innerCodec = (Codec) innerCodec; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java index d9675e89..1b978227 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java @@ -9,6 +9,7 @@ import javax.naming.OperationNotSupportedException; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -18,8 +19,8 @@ public final class SparseObjectCodec extends CodecBase> { private final @NotNull Map propertyNamesMap; private final String @NotNull [] propertyNames; - public SparseObjectCodec(Codec[] innerCodecs, String @NotNull [] propertyNames) { - super((Class>) Map.of().getClass()); + public SparseObjectCodec(UUID id, Codec[] innerCodecs, String @NotNull [] propertyNames) { + super(id, (Class>) Map.of().getClass()); this.innerCodecs = innerCodecs; this.propertyNames = propertyNames; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java index db255f3f..e19a264f 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java @@ -9,13 +9,15 @@ import javax.naming.OperationNotSupportedException; +import java.util.UUID; + import static com.edgedb.driver.util.BinaryProtocolUtils.INT_SIZE; public final class TupleCodec extends CodecBase { public final Codec[] innerCodecs; - public TupleCodec(Codec[] codecs) { - super(Tuple.class); + public TupleCodec(UUID id, Codec[] codecs) { + super(id, Tuple.class); this.innerCodecs = codecs; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java index 5c80da2b..d6a045f7 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java @@ -18,14 +18,14 @@ public abstract class ComplexCodecBase extends CodecBase implements Comple protected final @NotNull RuntimeCodecFactory runtimeFactory; @SafeVarargs - public ComplexCodecBase(Class cls, ComplexCodecConverter... converters) { - this(cls, null, converters); + public ComplexCodecBase(UUID id, Class cls, ComplexCodecConverter... converters) { + this(id, cls, null, converters); } @SuppressWarnings({"rawtypes", "unchecked"}) @SafeVarargs - public ComplexCodecBase(Class cls, @Nullable RuntimeCodecFactory runtimeFactory, ComplexCodecConverter @NotNull ... converters) { - super(cls); + public ComplexCodecBase(UUID id, Class cls, @Nullable RuntimeCodecFactory runtimeFactory, ComplexCodecConverter @NotNull ... converters) { + super(id, cls); this.runtimeFactory = runtimeFactory == null ? (cls1, parent, converter) -> new RuntimeCodecImpl(cls1, parent, converter) @@ -80,7 +80,7 @@ private final class RuntimeCodecImpl extends CodecBase implements RuntimeC public RuntimeCodecImpl(Class cls, ComplexCodecBase parent, ComplexCodecConverter converter) { - super(cls); + super(parent.id, cls); this.parent = parent; this.converter = converter; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java index afdb92db..c84af070 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java @@ -13,15 +13,17 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import static org.joou.Unsigned.uint; import static org.joou.Unsigned.ushort; public final class BigIntCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000110"); private static final BigInteger BASE = new BigInteger("10000"); public BigIntCodec() { - super(BigInteger.class); + super(ID, BigInteger.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java index a6722e9a..66069a91 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java @@ -7,10 +7,12 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class BoolCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000109"); public BoolCodec() { - super(Boolean.class); + super(ID, Boolean.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/BytesCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BytesCodec.java similarity index 87% rename from src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/BytesCodec.java rename to src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BytesCodec.java index 60d4becf..40466f0c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/BytesCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BytesCodec.java @@ -1,17 +1,18 @@ -package com.edgedb.driver.binary.codecs.scalars.complex; +package com.edgedb.driver.binary.codecs.scalars; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; -import com.edgedb.driver.binary.codecs.scalars.ScalarCodecBase; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class BytesCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000102"); public BytesCodec() { - super(Byte[].class); + super(ID, Byte[].class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java index f1a376aa..725adbbc 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java @@ -10,10 +10,12 @@ import javax.naming.OperationNotSupportedException; import java.time.Period; +import java.util.UUID; public final class DateDurationCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000112"); public DateDurationCodec() { - super(Period.class); + super(ID, Period.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java index ba4f0e38..8a5d6f2d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java @@ -10,12 +10,14 @@ import javax.naming.OperationNotSupportedException; import java.math.BigDecimal; +import java.util.UUID; import static org.joou.Unsigned.ushort; public final class DecimalCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000108"); public DecimalCodec() { - super(BigDecimal.class); + super(ID, BigDecimal.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java index 03c605ca..06b33801 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java @@ -10,10 +10,12 @@ import javax.naming.OperationNotSupportedException; import java.time.Duration; import java.time.temporal.ChronoUnit; +import java.util.UUID; public final class DurationCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010E"); public DurationCodec() { - super(Duration.class); + super(ID, Duration.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java index 6d33b4c2..4482f12c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java @@ -7,10 +7,12 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class Float32Codec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000106"); public Float32Codec() { - super(Float.class); + super(ID, Float.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java index 5680ecd9..26a15e9f 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java @@ -7,10 +7,12 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class Float64Codec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000107"); public Float64Codec() { - super(Double.class); + super(ID, Double.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java index 021b2aa0..d343b7a7 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java @@ -7,10 +7,12 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class Integer16Codec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000103"); public Integer16Codec() { - super(Short.class); + super(ID, Short.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java index 0fa59aba..e0cfea56 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java @@ -7,10 +7,13 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class Integer32Codec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000104"); + public Integer32Codec() { - super(Integer.class); + super(ID, Integer.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java index 85e052ef..dd43d5c8 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java @@ -1,16 +1,18 @@ package com.edgedb.driver.binary.codecs.scalars; -import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class Integer64Codec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000105"); public Integer64Codec() { - super(Long.class); + super(ID, Long.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java index 963875bb..bbe2fc66 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java @@ -10,12 +10,14 @@ import javax.naming.OperationNotSupportedException; import java.nio.charset.StandardCharsets; +import java.util.UUID; public class JsonCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010F"); private static final byte JSON_FORMAT = (byte)0x01; public JsonCodec() { - super(Json.class); + super(ID, Json.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java index f385ac9e..1634957a 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java @@ -10,10 +10,12 @@ import javax.naming.OperationNotSupportedException; import java.time.LocalDate; import java.time.temporal.ChronoUnit; +import java.util.UUID; public final class LocalDateCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010C"); public LocalDateCodec() { - super(LocalDate.class); + super(ID, LocalDate.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java index 4de0fa71..88a415da 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java @@ -10,10 +10,13 @@ import javax.naming.OperationNotSupportedException; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; +import java.util.UUID; public final class LocalDateTimeCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010B"); + public LocalDateTimeCodec() { - super(LocalDateTime.class); + super(ID, LocalDateTime.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java index 7d2e77e0..fd3526ce 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java @@ -9,10 +9,13 @@ import javax.naming.OperationNotSupportedException; import java.time.LocalTime; import java.time.temporal.ChronoUnit; +import java.util.UUID; public final class LocalTimeCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010D"); + public LocalTimeCodec() { - super(LocalTime.class); + super(ID, LocalTime.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java index de3842ae..bf6dc629 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java @@ -8,10 +8,13 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public final class MemoryCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000130"); + public MemoryCodec() { - super(Memory.class); + super(ID, Memory.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java index 39e958a5..a626a0d4 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java @@ -2,8 +2,10 @@ import com.edgedb.driver.binary.codecs.CodecBase; +import java.util.UUID; + public abstract class ScalarCodecBase extends CodecBase implements ScalarCodec { - public ScalarCodecBase(Class cls) { - super(cls); + public ScalarCodecBase(UUID id, Class cls) { + super(id, cls); } } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java index aceec61b..987d54f7 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java @@ -8,10 +8,13 @@ import javax.naming.OperationNotSupportedException; import java.nio.charset.StandardCharsets; +import java.util.UUID; public final class TextCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000101"); + public TextCodec() { - super(String.class); + super(ID, String.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java index 150d13f0..8c5b9117 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java @@ -10,8 +10,9 @@ import java.util.UUID; public final class UUIDCodec extends ScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000100"); public UUIDCodec() { - super(UUID.class); + super(ID, UUID.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java index deee139f..9dfd1ac9 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java @@ -13,11 +13,12 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.UUID; public abstract class ComplexScalarCodecBase extends ComplexCodecBase implements ScalarCodec { @SuppressWarnings({"unchecked", "rawtypes"}) - public ComplexScalarCodecBase(Class cls, ComplexCodecConverter... converters) { - super(cls, (c, p, cv) -> new RuntimeScalarCodecImpl(c, p, cv), converters); + public ComplexScalarCodecBase(UUID id, Class cls, ComplexCodecConverter... converters) { + super(id, cls, (c, p, cv) -> new RuntimeScalarCodecImpl(c, p, cv), converters); } } @@ -28,7 +29,7 @@ final class RuntimeScalarCodecImpl extends ScalarCodecBase implements R public RuntimeScalarCodecImpl(Class cls, ComplexCodecBase parent, ComplexCodecConverter converter) { - super(cls); + super(parent.id, cls); this.parent = parent; this.converter = converter; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java index e8646df7..2c804211 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java @@ -1,7 +1,7 @@ package com.edgedb.driver.binary.codecs.scalars.complex; -import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.codecs.complex.ComplexCodecConverter; import com.edgedb.driver.util.TemporalUtils; @@ -11,11 +11,15 @@ import javax.naming.OperationNotSupportedException; import java.time.OffsetDateTime; import java.time.ZonedDateTime; +import java.util.UUID; public final class DateTimeCodec extends ComplexScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010A"); + @SuppressWarnings("unchecked") public DateTimeCodec() { super( + ID, OffsetDateTime.class, new ComplexCodecConverter<>( ZonedDateTime.class, diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java index 4dcf52dc..675254e3 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java @@ -11,11 +11,15 @@ import javax.naming.OperationNotSupportedException; import java.time.Duration; import java.time.Period; +import java.util.UUID; public final class RelativeDurationCodec extends ComplexScalarCodecBase { + public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000111"); + @SuppressWarnings("unchecked") public RelativeDurationCodec() { super( + ID, RelativeDuration.class, new ComplexCodecConverter<>( Period.class, diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecAncestor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecAncestor.java new file mode 100644 index 00000000..b5c1d814 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecAncestor.java @@ -0,0 +1,14 @@ +package com.edgedb.driver.binary.protocol.common.descriptors; + +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; + +public final class CodecAncestor { + public final Codec codec; + public final TypeDescriptorInfo descriptor; + + public CodecAncestor(Codec codec, TypeDescriptorInfo descriptor) { + this.codec = codec; + this.descriptor = descriptor; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java new file mode 100644 index 00000000..a53b3ef3 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java @@ -0,0 +1,19 @@ +package com.edgedb.driver.binary.protocol.common.descriptors; + +public final class CodecMetadata { + public final String schemaName; + public final boolean isSchemaDefined; + public final CodecAncestor[] ancestors; + + public CodecMetadata(String schemaName, boolean isSchemaDefined) { + this.schemaName = schemaName; + this.isSchemaDefined = isSchemaDefined; + this.ancestors = new CodecAncestor[0]; + } + + public CodecMetadata(String schemaName, boolean isSchemaDefined, CodecAncestor[] ancestors) { + this.schemaName = schemaName; + this.isSchemaDefined = isSchemaDefined; + this.ancestors = ancestors; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElement.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/ShapeElement.java similarity index 84% rename from src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElement.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/ShapeElement.java index e0c29a37..1d101082 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElement.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/ShapeElement.java @@ -1,7 +1,8 @@ -package com.edgedb.driver.binary.protocol.v1.descriptors.common; +package com.edgedb.driver.binary.protocol.common.descriptors; import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.descriptors.ShapeElementFlags; import org.jetbrains.annotations.NotNull; import org.joou.UInteger; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElementFlags.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/ShapeElementFlags.java similarity index 88% rename from src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElementFlags.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/ShapeElementFlags.java index 432548ba..09a98c88 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/ShapeElementFlags.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/ShapeElementFlags.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.protocol.v1.descriptors.common; +package com.edgedb.driver.binary.protocol.common.descriptors; import com.edgedb.driver.binary.BinaryEnum; import org.joou.UInteger; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/TupleElement.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/TupleElement.java similarity index 84% rename from src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/TupleElement.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/TupleElement.java index c6d4c0df..683b5ce0 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/common/TupleElement.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/TupleElement.java @@ -1,4 +1,4 @@ -package com.edgedb.driver.binary.protocol.v1.descriptors.common; +package com.edgedb.driver.binary.protocol.common.descriptors; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/TypeOperation.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/TypeOperation.java new file mode 100644 index 00000000..df46eb64 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/TypeOperation.java @@ -0,0 +1,19 @@ +package com.edgedb.driver.binary.protocol.common.descriptors; + +import com.edgedb.driver.binary.BinaryEnum; + +public enum TypeOperation implements BinaryEnum { + UNION(1), + INTERSECTION(2); + + private final byte value; + + TypeOperation(int value) { + this.value = (byte)(value & 0xFF); + } + + @Override + public Byte getValue() { + return this.value; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java index b185c7d8..0d543b5b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java @@ -118,7 +118,7 @@ public Receivable readPacket(ServerMessageType type, int length, PacketReader re } @Override - public TypeDescriptorInfo readDescriptor(PacketReader reader) throws UnexpectedMessageException { + public TypeDescriptorInfo> readDescriptor(PacketReader reader) throws UnexpectedMessageException { var type = reader.readEnum(DescriptorType.class, Byte.TYPE); var id = reader.readUUID(); @@ -144,8 +144,9 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th case ARRAY_TYPE_DESCRIPTOR: var arrayType = descriptor.as(ArrayTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), id -> new CompilableCodec( + id, getRelativeCodec.apply(arrayType.typePosition.intValue()), ArrayCodec::new, t -> Array.newInstance(t,0).getClass() @@ -167,7 +168,11 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th inputShapeNames[i] = inputShape.shapes[i].name; } - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new SparseObjectCodec(inputShapeCodecs, inputShapeNames)); + return CodecBuilder.getOrCreateCodec( + this, + descriptor.getId(), + id -> new SparseObjectCodec(id, inputShapeCodecs, inputShapeNames) + ); case TUPLE_TYPE_DESCRIPTOR: var tupleType = descriptor.as(TupleTypeDescriptor.class); var innerCodecs = new Codec[tupleType.elementTypeDescriptorPositions.length]; @@ -176,7 +181,11 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th innerCodecs[i] = getRelativeCodec.apply(tupleType.elementTypeDescriptorPositions[i].intValue()); } - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new TupleCodec(innerCodecs)); + return CodecBuilder.getOrCreateCodec( + this, + descriptor.getId(), + id -> new TupleCodec(id, innerCodecs) + ); case NAMED_TUPLE_DESCRIPTOR: { var tupleShape = descriptor.as(NamedTupleTypeDescriptor.class); @@ -192,7 +201,11 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th ); } - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new ObjectCodec(elements)); + return CodecBuilder.getOrCreateCodec( + this, + descriptor.getId(), + id -> new ObjectCodec(id, elements) + ); } case OBJECT_SHAPE_DESCRIPTOR: { @@ -209,13 +222,18 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th ); } - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> new ObjectCodec(elements)); + return CodecBuilder.getOrCreateCodec( + this, + descriptor.getId(), + id -> new ObjectCodec(id, elements) + ); } case RANGE_TYPE_DESCRIPTOR: var rangeType = descriptor.as(RangeTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), id -> new CompilableCodec( + id, getRelativeCodec.apply(rangeType.typePosition.intValue()), RangeCodec::new, t -> Range.empty(t).getClass() @@ -226,8 +244,9 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th case SET_DESCRIPTOR: var setTypes = descriptor.as(SetTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), () -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), id -> new CompilableCodec( + id, getRelativeCodec.apply(setTypes.typePosition.intValue()), SetCodec::new, t -> Array.newInstance(t, 0).getClass() diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java index 774fd8e8..368c4462 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/InputShapeDescriptor.java @@ -1,7 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.protocol.TypeDescriptor; -import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; +import com.edgedb.driver.binary.protocol.common.descriptors.ShapeElement; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java index 0f82b1a7..1198f2f9 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/NamedTupleTypeDescriptor.java @@ -2,7 +2,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.protocol.TypeDescriptor; -import com.edgedb.driver.binary.protocol.v1.descriptors.common.TupleElement; +import com.edgedb.driver.binary.protocol.common.descriptors.TupleElement; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java index 539c64bf..9e8afc5b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/descriptors/ObjectShapeDescriptor.java @@ -1,7 +1,7 @@ package com.edgedb.driver.binary.protocol.v1.descriptors; import com.edgedb.driver.binary.protocol.TypeDescriptor; -import com.edgedb.driver.binary.protocol.v1.descriptors.common.ShapeElement; +import com.edgedb.driver.binary.protocol.common.descriptors.ShapeElement; import com.edgedb.driver.binary.PacketReader; import org.jetbrains.annotations.NotNull; import org.joou.UShort; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java new file mode 100644 index 00000000..e74db216 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java @@ -0,0 +1,109 @@ +package com.edgedb.driver.binary.protocol.v2; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.builders.CodecBuilder; +import com.edgedb.driver.binary.codecs.ArrayCodec; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.codecs.CompilableCodec; +import com.edgedb.driver.binary.protocol.ProtocolProvider; +import com.edgedb.driver.binary.protocol.ProtocolVersion; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.v1.V1ProtocolProvider; +import com.edgedb.driver.binary.protocol.v2.descriptors.*; +import com.edgedb.driver.clients.EdgeDBBinaryClient; +import com.edgedb.driver.exceptions.MissingCodecException; +import com.edgedb.driver.exceptions.UnexpectedMessageException; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Array; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class V2ProtocolProvider extends V1ProtocolProvider implements ProtocolProvider { + private static final Logger logger = LoggerFactory.getLogger(V1ProtocolProvider.class); + + private static final Map> TYPE_DESCRIPTOR_MAP; + + static { + TYPE_DESCRIPTOR_MAP = new HashMap<>(){{ + put(DescriptorType.ARRAY, ArrayTypeDescriptor::new); + put(DescriptorType.COMPOUND, CompoundTypeDescriptor::new); + put(DescriptorType.ENUMERATION, EnumerationTypeDescriptor::new); + put(DescriptorType.INPUT, InputShapeDescriptor::new); + put(DescriptorType.NAMED_TUPLE, NamedTupleTypeDescriptor::new); + put(DescriptorType.OBJECT_OUTPUT, ObjectOutputShapeDescriptor::new); + put(DescriptorType.OBJECT, ObjectTypeDescriptor::new); + put(DescriptorType.RANGE, RangeTypeDescriptor::new); + put(DescriptorType.SCALAR, ScalarTypeDescriptor::new); + put(DescriptorType.SET, SetDescriptor::new); + put(DescriptorType.TUPLE, TupleTypeDescriptor::new); + put(DescriptorType.TYPE_ANNOTATION_TEXT, (ignored, reader) -> new TypeAnnotationTextDescriptor(reader)); + }}; + } + + @Override + public ProtocolVersion getVersion() { + return ProtocolVersion.of(2, 0); + } + + public V2ProtocolProvider(EdgeDBBinaryClient client) { + super(client); + } + + @Override + public TypeDescriptorInfo readDescriptor(PacketReader reader) throws UnexpectedMessageException { + var type = reader.readEnum(DescriptorType.class, Byte.TYPE); + + var id = type == DescriptorType.TYPE_ANNOTATION_TEXT ? null : reader.readUUID(); + + if(!TYPE_DESCRIPTOR_MAP.containsKey(type)) { + logger.error("Unknown type descriptor {}", type); + throw new UnexpectedMessageException("Unsupported descriptor type " + type); + } + + return new TypeDescriptorInfo<>(TYPE_DESCRIPTOR_MAP.get(type).apply(id, reader), type); + } + + @SuppressWarnings("unchecked") + @Override + public @Nullable > Codec buildCodec( + TypeDescriptorInfo descriptorInfo, + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) throws MissingCodecException { + if(!(descriptorInfo.type instanceof DescriptorType)) { + throw new IllegalArgumentException("Expected v1 descriptor type, got " + descriptorInfo.type.getClass().getName()); + } + + var metadata = descriptorInfo.descriptor instanceof MetadataDescriptor + ? ((MetadataDescriptor)descriptorInfo.descriptor).getMetadata(getRelativeCodec, getRelativeDescriptor) + : null; + + switch ((DescriptorType)descriptorInfo.type) { + case ARRAY: + var arrayDescriptor = descriptorInfo.as(ArrayTypeDescriptor.class); + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + id -> new CompilableCodec( + id, + getRelativeCodec.apply(arrayDescriptor.type.intValue()), + ArrayCodec::new, + t -> Array.newInstance(t, 0).getClass() + ) + ); + case COMPOUND: + var compoundDescriptor = descriptorInfo.as(CompoundTypeDescriptor.class); + + return + + } + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ArrayTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ArrayTypeDescriptor.java new file mode 100644 index 00000000..7247db03 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ArrayTypeDescriptor.java @@ -0,0 +1,47 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.NotNull; +import org.joou.UShort; + +import java.util.UUID; +import java.util.function.Function; + +public final class ArrayTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + public final UShort[] ancestors; + public final UShort type; + public final Integer[] dimensions; + + public ArrayTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + this.ancestors = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + this.type = reader.readUInt16(); + this.dimensions = reader.readArrayOf(Integer.class, PacketReader::readInt32, UShort.class); + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + return new CodecMetadata( + name, + isSchemaDefined, + MetadataDescriptor.constructAncestors(ancestors, getRelativeCodec, getRelativeDescriptor) + ); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java new file mode 100644 index 00000000..f44b9a4e --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java @@ -0,0 +1,42 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import com.edgedb.driver.binary.protocol.common.descriptors.TypeOperation; +import org.jetbrains.annotations.NotNull; +import org.joou.UShort; + +import java.util.UUID; +import java.util.function.Function; + +public final class CompoundTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + public final TypeOperation operation; + public final UShort[] components; + + public CompoundTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + this.operation = reader.readEnum(TypeOperation.class, Byte.class); + this.components = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + return new CodecMetadata(name, isSchemaDefined); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java new file mode 100644 index 00000000..744f0b77 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java @@ -0,0 +1,29 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.BinaryEnum; + +public enum DescriptorType implements BinaryEnum { + SET(0), + OBJECT_OUTPUT(1), + SCALAR(3), + TUPLE(4), + NAMED_TUPLE(5), + ARRAY(6), + ENUMERATION(7), + INPUT(8), + RANGE(9), + OBJECT(10), + COMPOUND(11), + TYPE_ANNOTATION_TEXT(127); + + private byte value; + + DescriptorType(int value) { + this.value = (byte)(value & 0xFF); + } + + @Override + public Byte getValue() { + return this.value; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/EnumerationTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/EnumerationTypeDescriptor.java new file mode 100644 index 00000000..c50c5b75 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/EnumerationTypeDescriptor.java @@ -0,0 +1,45 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.NotNull; +import org.joou.UShort; + +import java.util.UUID; +import java.util.function.Function; + +public final class EnumerationTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + public final UShort[] ancestors; + public final String[] members; + + public EnumerationTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + this.ancestors = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + this.members = reader.readArrayOf(String.class, PacketReader::readString, UShort.class); + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, Function> getRelativeDescriptor + ) { + return new CodecMetadata( + name, + isSchemaDefined, + MetadataDescriptor.constructAncestors(ancestors, getRelativeCodec, getRelativeDescriptor) + ); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/InputShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/InputShapeDescriptor.java new file mode 100644 index 00000000..87517880 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/InputShapeDescriptor.java @@ -0,0 +1,23 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.common.descriptors.ShapeElement; +import org.joou.UShort; + +import java.util.UUID; + +public class InputShapeDescriptor implements TypeDescriptor { + public final UUID id; + public final ShapeElement[] elements; + + public InputShapeDescriptor(UUID id, PacketReader reader) { + this.id = id; + elements = reader.readArrayOf(ShapeElement.class, ShapeElement::new, UShort.class); + } + + @Override + public UUID getId() { + return this.id; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/MetadataDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/MetadataDescriptor.java new file mode 100644 index 00000000..d9e022be --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/MetadataDescriptor.java @@ -0,0 +1,34 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecAncestor; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.Nullable; +import org.joou.UShort; + +import java.util.function.Function; + +public interface MetadataDescriptor { + static CodecAncestor[] constructAncestors( + UShort[] ancestors, + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + var codecAncestors = new CodecAncestor[ancestors.length]; + + for(var i = 0; i != ancestors.length; i++) { + codecAncestors[i] = new CodecAncestor( + getRelativeCodec.apply(ancestors[i].intValue()), + getRelativeDescriptor.apply(ancestors[i].intValue()) + ); + } + + return codecAncestors; + } + + @Nullable CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ); +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java new file mode 100644 index 00000000..ac6c3a1a --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java @@ -0,0 +1,46 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import com.edgedb.driver.binary.protocol.common.descriptors.TupleElement; +import org.jetbrains.annotations.NotNull; +import org.joou.UShort; + +import java.util.UUID; +import java.util.function.Function; + +public final class NamedTupleTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + public final UShort[] ancestors; + public final TupleElement[] elements; + + public NamedTupleTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + this.ancestors = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + this.elements = reader.readArrayOf(TupleElement.class, TupleElement::new, UShort.class); + } + + @Override + public UUID getId() { + return null; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + return new CodecMetadata( + name, + isSchemaDefined, + MetadataDescriptor.constructAncestors(ancestors, getRelativeCodec, getRelativeDescriptor) + ); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectOutputShapeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectOutputShapeDescriptor.java new file mode 100644 index 00000000..e9a7491d --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectOutputShapeDescriptor.java @@ -0,0 +1,26 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import org.joou.UShort; + +import java.util.UUID; + +public final class ObjectOutputShapeDescriptor implements TypeDescriptor { + public final UUID id; + public final boolean isEphemeralFreeShape; + public final UShort type; + public final ShapeElement[] elements; + + public ObjectOutputShapeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.isEphemeralFreeShape = reader.readBoolean(); + this.type = reader.readUInt16(); + this.elements = reader.readArrayOf(ShapeElement.class, ShapeElement::new, UShort.class); + } + + @Override + public UUID getId() { + return this.id; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java new file mode 100644 index 00000000..ce74a7dc --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java @@ -0,0 +1,39 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; +import java.util.function.Function; + +public final class ObjectTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + + public ObjectTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + } + + @Override + public UUID getId() { + return null; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + return new CodecMetadata( + name, + isSchemaDefined + ); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/RangeTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/RangeTypeDescriptor.java new file mode 100644 index 00000000..744b855b --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/RangeTypeDescriptor.java @@ -0,0 +1,45 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.NotNull; +import org.joou.UShort; + +import java.util.UUID; +import java.util.function.Function; + +public final class RangeTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + public final UShort[] ancestors; + public final UShort type; + + public RangeTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + this.ancestors = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + this.type = reader.readUInt16(); + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + return new CodecMetadata( + name, + isSchemaDefined, + MetadataDescriptor.constructAncestors(ancestors, getRelativeCodec, getRelativeDescriptor) + ); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ScalarTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ScalarTypeDescriptor.java new file mode 100644 index 00000000..faa3e5f2 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ScalarTypeDescriptor.java @@ -0,0 +1,43 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.NotNull; +import org.joou.UShort; + +import java.util.UUID; +import java.util.function.Function; + +public final class ScalarTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + public final UShort[] ancestors; + + public ScalarTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + this.ancestors = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + return new CodecMetadata( + name, + isSchemaDefined, + MetadataDescriptor.constructAncestors(ancestors, getRelativeCodec, getRelativeDescriptor) + ); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetDescriptor.java new file mode 100644 index 00000000..91b02c5f --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetDescriptor.java @@ -0,0 +1,22 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import org.joou.UShort; + +import java.util.UUID; + +public final class SetDescriptor implements TypeDescriptor { + public final UUID id; + public final UShort type; + + public SetDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.type = reader.readUInt16(); + } + + @Override + public UUID getId() { + return this.id; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java new file mode 100644 index 00000000..98a200f8 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java @@ -0,0 +1,23 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.descriptors.ShapeElementFlags; +import org.joou.UInteger; +import org.joou.UShort; + +public final class ShapeElement { + public final ShapeElementFlags flags; + public final Cardinality cardinality; + public final String name; + public final UShort typePosition; + public final UShort sourceTypePosition; + + public ShapeElement(PacketReader reader) { + this.flags = reader.readEnum(ShapeElementFlags.class, UInteger.class); + this.cardinality = reader.readEnum(Cardinality.class, Byte.class); + this.name = reader.readString(); + this.typePosition = reader.readUInt16(); + this.sourceTypePosition = reader.readUInt16(); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TupleTypeDescriptor.java new file mode 100644 index 00000000..6155193f --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TupleTypeDescriptor.java @@ -0,0 +1,45 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.codecs.Codec; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.NotNull; +import org.joou.UShort; + +import java.util.UUID; +import java.util.function.Function; + +public final class TupleTypeDescriptor implements TypeDescriptor, MetadataDescriptor { + public final UUID id; + public final String name; + public final boolean isSchemaDefined; + public final UShort[] ancestors; + public final UShort[] elements; + + public TupleTypeDescriptor(UUID id, PacketReader reader) { + this.id = id; + this.name = reader.readString(); + this.isSchemaDefined = reader.readBoolean(); + this.ancestors = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + this.elements = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public @NotNull CodecMetadata getMetadata( + Function> getRelativeCodec, + Function> getRelativeDescriptor + ) { + return new CodecMetadata( + name, + isSchemaDefined, + MetadataDescriptor.constructAncestors(ancestors, getRelativeCodec, getRelativeDescriptor) + ); + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TypeAnnotationTextDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TypeAnnotationTextDescriptor.java new file mode 100644 index 00000000..e66320ef --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/TypeAnnotationTextDescriptor.java @@ -0,0 +1,27 @@ +package com.edgedb.driver.binary.protocol.v2.descriptors; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.builders.CodecBuilder; +import com.edgedb.driver.binary.protocol.TypeDescriptor; +import org.joou.UShort; + +import java.util.UUID; + +public final class TypeAnnotationTextDescriptor implements TypeDescriptor { + public final UUID id; + public final UShort descriptor; + public final String key; + public final String value; + + public TypeAnnotationTextDescriptor(PacketReader reader) { + this.id = CodecBuilder.NULL_CODEC_ID; + this.descriptor = reader.readUInt16(); + this.key = reader.readString(); + this.value = reader.readString(); + } + + @Override + public UUID getId() { + return this.id; + } +} From 00d1be413bdbabd8531bf6c74a4df68c56a1a49f Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Fri, 28 Jul 2023 12:19:33 -0300 Subject: [PATCH 05/10] v2 protocol implemented --- .../driver/binary/builders/CodecBuilder.java | 33 ++- .../driver/binary/codecs/ArrayCodec.java | 5 +- .../edgedb/driver/binary/codecs/Codec.java | 3 + .../driver/binary/codecs/CodecBase.java | 11 +- .../driver/binary/codecs/CompilableCodec.java | 13 +- .../driver/binary/codecs/CompoundCodec.java | 17 +- .../binary/codecs/EnumerationCodec.java | 43 ++++ .../driver/binary/codecs/NullCodec.java | 6 + .../driver/binary/codecs/ObjectCodec.java | 9 +- .../driver/binary/codecs/RangeCodec.java | 5 +- .../edgedb/driver/binary/codecs/SetCodec.java | 5 +- .../binary/codecs/SparseObjectCodec.java | 5 +- .../driver/binary/codecs/TupleCodec.java | 5 +- .../codecs/complex/ComplexCodecBase.java | 11 +- .../binary/codecs/scalars/BigIntCodec.java | 5 +- .../binary/codecs/scalars/BoolCodec.java | 5 +- .../binary/codecs/scalars/BytesCodec.java | 5 +- .../codecs/scalars/DateDurationCodec.java | 5 +- .../binary/codecs/scalars/DecimalCodec.java | 5 +- .../binary/codecs/scalars/DurationCodec.java | 5 +- .../binary/codecs/scalars/Float32Codec.java | 5 +- .../binary/codecs/scalars/Float64Codec.java | 5 +- .../binary/codecs/scalars/Integer16Codec.java | 5 +- .../binary/codecs/scalars/Integer32Codec.java | 5 +- .../binary/codecs/scalars/Integer64Codec.java | 5 +- .../binary/codecs/scalars/JsonCodec.java | 5 +- .../binary/codecs/scalars/LocalDateCodec.java | 5 +- .../codecs/scalars/LocalDateTimeCodec.java | 5 +- .../binary/codecs/scalars/LocalTimeCodec.java | 5 +- .../binary/codecs/scalars/MemoryCodec.java | 5 +- .../codecs/scalars/ScalarCodecBase.java | 6 +- .../binary/codecs/scalars/TextCodec.java | 11 +- .../binary/codecs/scalars/UUIDCodec.java | 5 +- .../complex/ComplexScalarCodecBase.java | 7 +- .../codecs/scalars/complex/DateTimeCodec.java | 4 +- .../complex/RelativeDurationCodec.java | 4 +- .../binary/protocol/ProtocolProvider.java | 2 + .../protocol/v1/V1ProtocolProvider.java | 23 ++- .../protocol/v2/V2ProtocolProvider.java | 195 +++++++++++++++++- 39 files changed, 418 insertions(+), 90 deletions(-) create mode 100644 src/driver/src/main/java/com/edgedb/driver/binary/codecs/EnumerationCodec.java diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java index 88a33004..ac89cde0 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java @@ -4,7 +4,6 @@ import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.codecs.NullCodec; import com.edgedb.driver.binary.codecs.scalars.*; -import com.edgedb.driver.binary.codecs.scalars.BytesCodec; import com.edgedb.driver.binary.codecs.scalars.complex.DateTimeCodec; import com.edgedb.driver.binary.codecs.scalars.complex.RelativeDurationCodec; import com.edgedb.driver.binary.protocol.ProtocolProvider; @@ -12,6 +11,7 @@ import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; import com.edgedb.driver.binary.protocol.common.Cardinality; import com.edgedb.driver.binary.protocol.common.IOFormat; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.exceptions.MissingCodecException; @@ -28,6 +28,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -201,15 +202,35 @@ public static void updateCachedCodecs(ProtocolProvider provider, long cacheKey, } @SuppressWarnings("unchecked") - public static Codec getOrCreateCodec(ProtocolProvider provider, UUID id, @NotNull Supplier> constructor) { + public static Codec getOrCreateCodec( + ProtocolProvider provider, + UUID id, + @NotNull Supplier> constructor + ) { return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) .codecPartsInstanceCache.computeIfAbsent(id, ignored -> constructor.get()); } @SuppressWarnings("unchecked") - public static Codec getOrCreateCodec(ProtocolProvider provider, UUID id, @NotNull Function> constructor) { + public static Codec getOrCreateCodec( + ProtocolProvider provider, + UUID id, + @Nullable CodecMetadata metadata, + @NotNull Function<@Nullable CodecMetadata, Codec> constructor + ) { return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) - .codecPartsInstanceCache.computeIfAbsent(id, constructor); + .codecPartsInstanceCache.computeIfAbsent(id, ignored -> constructor.apply(metadata)); + } + + @SuppressWarnings("unchecked") + public static Codec getOrCreateCodec( + ProtocolProvider provider, + UUID id, + @Nullable CodecMetadata metadata, + @NotNull BiFunction> constructor + ) { + return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) + .codecPartsInstanceCache.computeIfAbsent(id, i -> constructor.apply(i, metadata)); } @SuppressWarnings("unchecked") @@ -218,12 +239,12 @@ public static Codec getOrCreateCodec(ProtocolProvider provider, UUID id, .codecPartsInstanceCache.computeIfAbsent( id, (v) -> scalarCodecFactories.containsKey(v) - ? scalarCodecFactories.get(v).get() + ? scalarCodecFactories.get(v).apply(null) : null ); } - private static final Map>> scalarCodecFactories = new HashMap<>() { + private static final Map>> scalarCodecFactories = new HashMap<>() { { put(UUID.fromString("00000000-0000-0000-0000-000000000100"), UUIDCodec::new); put(UUID.fromString("00000000-0000-0000-0000-000000000101"), TextCodec::new); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java index 38e5a562..25fd44cf 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; @@ -23,8 +24,8 @@ public class ArrayCodec extends CodecBase { private final Codec innerCodec; @SuppressWarnings("unchecked") - public ArrayCodec(UUID id, Class cls, Codec codec) { - super(id, (Class) cls); + public ArrayCodec(UUID id, @Nullable CodecMetadata metadata, Class cls, Codec codec) { + super(id, metadata, (Class) cls); this.innerCodec = (Codec) codec; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java index 60bbc0af..f74b1e25 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/Codec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; @@ -14,6 +15,8 @@ public interface Codec { UUID getId(); + @Nullable CodecMetadata getMetadata(); + void serialize(final PacketWriter writer, final @Nullable T value, final CodecContext context) throws OperationNotSupportedException, EdgeDBException; @Nullable T deserialize(final PacketReader reader, final CodecContext context) throws EdgeDBException, OperationNotSupportedException; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java index 77f1602d..a60649e8 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CodecBase.java @@ -1,17 +1,21 @@ package com.edgedb.driver.binary.codecs; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.Type; import java.util.UUID; public abstract class CodecBase implements Codec { public final UUID id; + public final @Nullable CodecMetadata metadata; private final Class cls; - public CodecBase(UUID id, Class cls) { + public CodecBase(UUID id, @Nullable CodecMetadata metadata, Class cls) { this.cls = cls; this.id = id; + this.metadata = metadata; } @Override @@ -19,6 +23,11 @@ public UUID getId() { return this.id; } + @Override + public @Nullable CodecMetadata getMetadata() { + return this.metadata; + } + @Override public Class getConvertingClass() { return this.cls; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java index d3ef04bd..c6bf57f2 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompilableCodec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,7 +17,7 @@ public final class CompilableCodec implements Codec { @FunctionalInterface public interface CompilableFactory { - Codec compile(UUID id, Class cls, Codec innerCodec); + Codec compile(UUID id, @Nullable CodecMetadata metadata, Class cls, Codec innerCodec); } private final Codec innerCodec; @@ -24,16 +25,19 @@ public interface CompilableFactory { private final @NotNull ConcurrentMap, Codec> instanceCache; private final Function, Class> compilableTypeFactory; private final UUID id; + private final @Nullable CodecMetadata metadata; private @Nullable Class compilableType; public CompilableCodec( UUID id, + @Nullable CodecMetadata metadata, Codec innerCodec, CompilableFactory factory, Function, Class> compilableTypeFactory ) { this.id = id; + this.metadata = metadata; this.factory = factory; this.innerCodec = innerCodec; this.instanceCache = new ConcurrentHashMap<>(); @@ -53,7 +57,7 @@ public Codec getInnerCodec() { } public Codec compile(Class cls, Codec innerCodec) { - return instanceCache.computeIfAbsent(cls, (c) -> this.factory.compile(this.id, c, innerCodec)); + return instanceCache.computeIfAbsent(cls, (c) -> this.factory.compile(this.id, this.metadata, c, innerCodec)); } public Class getInnerType() { @@ -67,6 +71,11 @@ public UUID getId() { return this.id; } + @Override + public @Nullable CodecMetadata getMetadata() { + return this.metadata; + } + @Override public void serialize(PacketWriter writer, @Nullable Object value, CodecContext context) throws OperationNotSupportedException { throw new OperationNotSupportedException(); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java index 20d9c6ed..9f36bb24 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.binary.protocol.common.descriptors.TypeOperation; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.Nullable; @@ -10,23 +11,29 @@ import java.util.UUID; public class CompoundCodec extends CodecBase { + private final TypeOperation operation; + private final Codec[] elements; public CompoundCodec( UUID id, - Class cls, + @Nullable CodecMetadata metadata, TypeOperation operation, - ) { - super(id, cls); + Codec[] elements + ) { + super(id, metadata, Object.class); + + this.operation = operation; + this.elements = elements; } @Override public void serialize(PacketWriter writer, @Nullable Object value, CodecContext context) throws OperationNotSupportedException, EdgeDBException { - + throw new OperationNotSupportedException("No data wire format has been defined for this type of codec"); } @Nullable @Override public Object deserialize(PacketReader reader, CodecContext context) throws EdgeDBException, OperationNotSupportedException { - return null; + throw new OperationNotSupportedException("No data wire format has been defined for this type of codec"); } } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/EnumerationCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/EnumerationCodec.java new file mode 100644 index 00000000..01898307 --- /dev/null +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/EnumerationCodec.java @@ -0,0 +1,43 @@ +package com.edgedb.driver.binary.codecs; + +import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.codecs.scalars.TextCodec; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.naming.OperationNotSupportedException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.UUID; + +public class EnumerationCodec extends TextCodec { + public final HashSet members; + + public EnumerationCodec(UUID id, @Nullable CodecMetadata metadata, String[] members) { + super(id, metadata); + + this.members = new HashSet<>(Arrays.asList(members)); + } + + @Override + public void serialize(@NotNull PacketWriter writer, @Nullable String value, CodecContext context) throws OperationNotSupportedException { + if(!members.contains(value)) { + throw new IllegalArgumentException("Value is not a member of the defined enumeration"); + } + + super.serialize(writer, value, context); + } + + @Override + public @NotNull String deserialize(@NotNull PacketReader reader, CodecContext context) { + var value = super.deserialize(reader, context); + + if(!members.contains(value)) { + throw new IllegalArgumentException("Value is not a member of the defined enumeration"); + } + + return value; + } +} diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java index 619abc85..2fc458b6 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/NullCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.builders.CodecBuilder; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,6 +18,11 @@ public UUID getId() { return CodecBuilder.NULL_CODEC_ID; } + @Override + public @Nullable CodecMetadata getMetadata() { + return null; + } + @Override public void serialize(@NotNull PacketWriter writer, @Nullable Void value, CodecContext context) throws OperationNotSupportedException { writer.write(0); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java index 10c3f1e3..638dcb04 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java @@ -6,6 +6,7 @@ import com.edgedb.driver.binary.builders.types.TypeBuilder; import com.edgedb.driver.binary.builders.types.TypeDeserializerInfo; import com.edgedb.driver.binary.protocol.common.Cardinality; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.exceptions.NoTypeConverterException; import org.jetbrains.annotations.NotNull; @@ -29,7 +30,7 @@ public static final class TypeInitializedObjectCodec extends ObjectCodec { private final @NotNull ObjectCodec parent; public TypeInitializedObjectCodec(@NotNull Class target, @NotNull ObjectCodec parent) throws EdgeDBException { - super(parent.id, parent.elements); + super(parent.id, parent.metadata, parent.elements); this.parent = parent; this.target = target; @@ -41,7 +42,7 @@ public TypeInitializedObjectCodec(@NotNull Class target, @NotNull ObjectCodec } public TypeInitializedObjectCodec(@NotNull TypeDeserializerInfo info, @NotNull ObjectCodec parent) { - super(parent.id, parent.elements); + super(parent.id, parent.metadata, parent.elements); this.parent = parent; this.target = info.getType(); @@ -88,8 +89,8 @@ public ObjectProperty(String name, Codec codec, @Nullable Cardinality cardina public final ObjectProperty[] elements; private final @NotNull ConcurrentMap, TypeInitializedObjectCodec> typeCodecs; - public ObjectCodec(UUID id, ObjectProperty... elements) { - super(id, Object.class); + public ObjectCodec(UUID id, @Nullable CodecMetadata metadata, ObjectProperty... elements) { + super(id, metadata, Object.class); this.elements = elements; this.typeCodecs = new ConcurrentHashMap<>(); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java index f17477dc..19033b5c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.common.RangeFlags; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.datatypes.Range; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.exceptions.EdgeDBException; @@ -18,8 +19,8 @@ public final class RangeCodec extends CodecBase> { private final Codec innerCodec; @SuppressWarnings("unchecked") - public RangeCodec(UUID id, Class cls, Codec innerCodec) { - super(id, (Class>) cls); + public RangeCodec(UUID id, @Nullable CodecMetadata metadata, Class cls, Codec innerCodec) { + super(id, metadata, (Class>) cls); this.innerCodec = (Codec) innerCodec; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java index a0f083c1..a1b4b618 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,8 +21,8 @@ public final class SetCodec extends CodecBase> { private final Codec innerCodec; @SuppressWarnings("unchecked") - public SetCodec(UUID id, Class cls, Codec innerCodec) { - super(id, (Class>) cls); + public SetCodec(UUID id, @Nullable CodecMetadata metadata, Class cls, Codec innerCodec) { + super(id, metadata, (Class>) cls); this.innerCodec = (Codec) innerCodec; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java index 1b978227..9dfd8239 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,8 +20,8 @@ public final class SparseObjectCodec extends CodecBase> { private final @NotNull Map propertyNamesMap; private final String @NotNull [] propertyNames; - public SparseObjectCodec(UUID id, Codec[] innerCodecs, String @NotNull [] propertyNames) { - super(id, (Class>) Map.of().getClass()); + public SparseObjectCodec(UUID id, @Nullable CodecMetadata metadata, Codec[] innerCodecs, String @NotNull [] propertyNames) { + super(id, metadata, (Class>) Map.of().getClass()); this.innerCodecs = innerCodecs; this.propertyNames = propertyNames; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java index e19a264f..616568a7 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java @@ -2,6 +2,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.datatypes.Tuple; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.NotNull; @@ -16,8 +17,8 @@ public final class TupleCodec extends CodecBase { public final Codec[] innerCodecs; - public TupleCodec(UUID id, Codec[] codecs) { - super(id, Tuple.class); + public TupleCodec(UUID id, @Nullable CodecMetadata metadata, Codec[] codecs) { + super(id, metadata, Tuple.class); this.innerCodecs = codecs; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java index d6a045f7..40e3fe25 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/complex/ComplexCodecBase.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.*; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,14 +19,14 @@ public abstract class ComplexCodecBase extends CodecBase implements Comple protected final @NotNull RuntimeCodecFactory runtimeFactory; @SafeVarargs - public ComplexCodecBase(UUID id, Class cls, ComplexCodecConverter... converters) { - this(id, cls, null, converters); + public ComplexCodecBase(UUID id, @Nullable CodecMetadata metadata, Class cls, ComplexCodecConverter... converters) { + this(id, metadata, cls, null, converters); } @SuppressWarnings({"rawtypes", "unchecked"}) @SafeVarargs - public ComplexCodecBase(UUID id, Class cls, @Nullable RuntimeCodecFactory runtimeFactory, ComplexCodecConverter @NotNull ... converters) { - super(id, cls); + public ComplexCodecBase(UUID id, @Nullable CodecMetadata metadata, Class cls, @Nullable RuntimeCodecFactory runtimeFactory, ComplexCodecConverter @NotNull ... converters) { + super(id, metadata, cls); this.runtimeFactory = runtimeFactory == null ? (cls1, parent, converter) -> new RuntimeCodecImpl(cls1, parent, converter) @@ -80,7 +81,7 @@ private final class RuntimeCodecImpl extends CodecBase implements RuntimeC public RuntimeCodecImpl(Class cls, ComplexCodecBase parent, ComplexCodecConverter converter) { - super(parent.id, cls); + super(parent.id, parent.metadata, cls); this.parent = parent; this.converter = converter; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java index c84af070..930980bd 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BigIntCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.util.StringsUtil; import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; @@ -22,8 +23,8 @@ public final class BigIntCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000110"); private static final BigInteger BASE = new BigInteger("10000"); - public BigIntCodec() { - super(ID, BigInteger.class); + public BigIntCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, BigInteger.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java index 66069a91..9575b85c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BoolCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,8 +12,8 @@ public final class BoolCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000109"); - public BoolCodec() { - super(ID, Boolean.class); + public BoolCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Boolean.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BytesCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BytesCodec.java index 40466f0c..e7535d86 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BytesCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/BytesCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,8 +12,8 @@ public final class BytesCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000102"); - public BytesCodec() { - super(ID, Byte[].class); + public BytesCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Byte[].class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java index 725adbbc..4a59b962 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DateDurationCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; @@ -14,8 +15,8 @@ public final class DateDurationCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000112"); - public DateDurationCodec() { - super(ID, Period.class); + public DateDurationCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Period.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java index 8a5d6f2d..fc108ed1 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DecimalCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.util.StringsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,8 +17,8 @@ public final class DecimalCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000108"); - public DecimalCodec() { - super(ID, BigDecimal.class); + public DecimalCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, BigDecimal.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java index 06b33801..452e840c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/DurationCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,8 +15,8 @@ public final class DurationCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010E"); - public DurationCodec() { - super(ID, Duration.class); + public DurationCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Duration.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java index 4482f12c..99f0eb03 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float32Codec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,8 +12,8 @@ public final class Float32Codec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000106"); - public Float32Codec() { - super(ID, Float.class); + public Float32Codec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Float.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java index 26a15e9f..6d0252b8 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Float64Codec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,8 +12,8 @@ public final class Float64Codec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000107"); - public Float64Codec() { - super(ID, Double.class); + public Float64Codec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Double.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java index d343b7a7..b866d802 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer16Codec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.PacketReader; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,8 +12,8 @@ public final class Integer16Codec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000103"); - public Integer16Codec() { - super(ID, Short.class); + public Integer16Codec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Short.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java index e0cfea56..459d66b5 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer32Codec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,8 +13,8 @@ public final class Integer32Codec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000104"); - public Integer32Codec() { - super(ID, Integer.class); + public Integer32Codec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Integer.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java index dd43d5c8..86240155 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/Integer64Codec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,8 +12,8 @@ public final class Integer64Codec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000105"); - public Integer64Codec() { - super(ID, Long.class); + public Integer64Codec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Long.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java index bbe2fc66..62ca6c4f 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/JsonCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.datatypes.Json; import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; @@ -16,8 +17,8 @@ public class JsonCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010F"); private static final byte JSON_FORMAT = (byte)0x01; - public JsonCodec() { - super(ID, Json.class); + public JsonCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Json.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java index 1634957a..69973fda 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.util.TemporalUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,8 +15,8 @@ public final class LocalDateCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010C"); - public LocalDateCodec() { - super(ID, LocalDate.class); + public LocalDateCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, LocalDate.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java index 88a415da..2d8ab2e5 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalDateTimeCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.util.TemporalUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,8 +16,8 @@ public final class LocalDateTimeCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010B"); - public LocalDateTimeCodec() { - super(ID, LocalDateTime.class); + public LocalDateTimeCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, LocalDateTime.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java index fd3526ce..5a3ac350 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/LocalTimeCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,8 +15,8 @@ public final class LocalTimeCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010D"); - public LocalTimeCodec() { - super(ID, LocalTime.class); + public LocalTimeCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, LocalTime.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java index bf6dc629..91d3f909 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/MemoryCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.datatypes.Memory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -13,8 +14,8 @@ public final class MemoryCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000130"); - public MemoryCodec() { - super(ID, Memory.class); + public MemoryCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, Memory.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java index a626a0d4..e0a2d34b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/ScalarCodecBase.java @@ -1,11 +1,13 @@ package com.edgedb.driver.binary.codecs.scalars; import com.edgedb.driver.binary.codecs.CodecBase; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; +import org.jetbrains.annotations.Nullable; import java.util.UUID; public abstract class ScalarCodecBase extends CodecBase implements ScalarCodec { - public ScalarCodecBase(UUID id, Class cls) { - super(id, cls); + public ScalarCodecBase(UUID id, @Nullable CodecMetadata metadata, Class cls) { + super(id, metadata, cls); } } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java index 987d54f7..ddcf8b0d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/TextCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -10,11 +11,15 @@ import java.nio.charset.StandardCharsets; import java.util.UUID; -public final class TextCodec extends ScalarCodecBase { +public class TextCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000101"); - public TextCodec() { - super(ID, String.class); + public TextCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, String.class); + } + + protected TextCodec(UUID id, @Nullable CodecMetadata metadata) { + super(id, metadata, String.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java index 8c5b9117..d496741b 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/UUIDCodec.java @@ -3,6 +3,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.CodecContext; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,8 +12,8 @@ public final class UUIDCodec extends ScalarCodecBase { public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-000000000100"); - public UUIDCodec() { - super(ID, UUID.class); + public UUIDCodec(@Nullable CodecMetadata metadata) { + super(ID, metadata, UUID.class); } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java index 9dfd1ac9..aff9f495 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/ComplexScalarCodecBase.java @@ -9,6 +9,7 @@ import com.edgedb.driver.binary.codecs.complex.ComplexCodecConverter; import com.edgedb.driver.binary.codecs.scalars.ScalarCodec; import com.edgedb.driver.binary.codecs.scalars.ScalarCodecBase; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.exceptions.EdgeDBException; import org.jetbrains.annotations.Nullable; @@ -17,8 +18,8 @@ public abstract class ComplexScalarCodecBase extends ComplexCodecBase implements ScalarCodec { @SuppressWarnings({"unchecked", "rawtypes"}) - public ComplexScalarCodecBase(UUID id, Class cls, ComplexCodecConverter... converters) { - super(id, cls, (c, p, cv) -> new RuntimeScalarCodecImpl(c, p, cv), converters); + public ComplexScalarCodecBase(UUID id, @Nullable CodecMetadata metadata, Class cls, ComplexCodecConverter... converters) { + super(id, metadata, cls, (c, p, cv) -> new RuntimeScalarCodecImpl(c, p, cv), converters); } } @@ -29,7 +30,7 @@ final class RuntimeScalarCodecImpl extends ScalarCodecBase implements R public RuntimeScalarCodecImpl(Class cls, ComplexCodecBase parent, ComplexCodecConverter converter) { - super(parent.id, cls); + super(parent.id, parent.metadata, cls); this.parent = parent; this.converter = converter; } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java index 2c804211..69b9aa35 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/DateTimeCodec.java @@ -4,6 +4,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.codecs.complex.ComplexCodecConverter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.util.TemporalUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,9 +18,10 @@ public final class DateTimeCodec extends ComplexScalarCodecBase public static final UUID ID = UUID.fromString("00000000-0000-0000-0000-00000000010A"); @SuppressWarnings("unchecked") - public DateTimeCodec() { + public DateTimeCodec(@Nullable CodecMetadata metadata) { super( ID, + metadata, OffsetDateTime.class, new ComplexCodecConverter<>( ZonedDateTime.class, diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java index 675254e3..31903fb6 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/scalars/complex/RelativeDurationCodec.java @@ -4,6 +4,7 @@ import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.codecs.complex.ComplexCodecConverter; +import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.datatypes.RelativeDuration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,9 +18,10 @@ public final class RelativeDurationCodec extends ComplexScalarCodecBase( Period.class, diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java index b48fe1af..c37a0134 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolProvider.java @@ -4,6 +4,7 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.codecs.Codec; import com.edgedb.driver.binary.protocol.v1.V1ProtocolProvider; +import com.edgedb.driver.binary.protocol.v2.V2ProtocolProvider; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.MissingCodecException; import com.edgedb.driver.exceptions.UnexpectedMessageException; @@ -22,6 +23,7 @@ public interface ProtocolProvider { ConcurrentMap> PROVIDERS_FACTORY = new ConcurrentHashMap<>(); Map> PROVIDERS = new HashMap<>(){{ put(ProtocolVersion.of(1, 0), V1ProtocolProvider::new); + put(ProtocolVersion.of(2, 0), V2ProtocolProvider::new); }}; static ProtocolProvider getProvider(EdgeDBBinaryClient client) { diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java index 0d543b5b..8c24a8ef 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java @@ -144,9 +144,10 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) case ARRAY_TYPE_DESCRIPTOR: var arrayType = descriptor.as(ArrayTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), id -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), null, (id, metadata) -> new CompilableCodec( id, + metadata, getRelativeCodec.apply(arrayType.typePosition.intValue()), ArrayCodec::new, t -> Array.newInstance(t,0).getClass() @@ -157,7 +158,7 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) // should be resolved by the above case, getting here is an error throw new MissingCodecException(String.format("Could not find the scalar type %s", descriptor.getId().toString())); case ENUMERATION_TYPE_DESCRIPTOR: - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), TextCodec::new); + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), null, TextCodec::new); case INPUT_SHAPE_DESCRIPTOR: var inputShape = descriptor.as(InputShapeDescriptor.class); var inputShapeCodecs = new Codec[inputShape.shapes.length]; @@ -171,7 +172,8 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) return CodecBuilder.getOrCreateCodec( this, descriptor.getId(), - id -> new SparseObjectCodec(id, inputShapeCodecs, inputShapeNames) + null, + (id, metadata) -> new SparseObjectCodec(id, metadata, inputShapeCodecs, inputShapeNames) ); case TUPLE_TYPE_DESCRIPTOR: var tupleType = descriptor.as(TupleTypeDescriptor.class); @@ -184,7 +186,8 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) return CodecBuilder.getOrCreateCodec( this, descriptor.getId(), - id -> new TupleCodec(id, innerCodecs) + null, + (id, metadata) -> new TupleCodec(id, metadata, innerCodecs) ); case NAMED_TUPLE_DESCRIPTOR: { @@ -204,7 +207,8 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) return CodecBuilder.getOrCreateCodec( this, descriptor.getId(), - id -> new ObjectCodec(id, elements) + null, + (id, metadata) -> new ObjectCodec(id, metadata, elements) ); } case OBJECT_SHAPE_DESCRIPTOR: @@ -225,15 +229,17 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) return CodecBuilder.getOrCreateCodec( this, descriptor.getId(), - id -> new ObjectCodec(id, elements) + null, + (id, metadata) -> new ObjectCodec(id, metadata, elements) ); } case RANGE_TYPE_DESCRIPTOR: var rangeType = descriptor.as(RangeTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), id -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), null, (id, metadata) -> new CompilableCodec( id, + metadata, getRelativeCodec.apply(rangeType.typePosition.intValue()), RangeCodec::new, t -> Range.empty(t).getClass() @@ -244,9 +250,10 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) case SET_DESCRIPTOR: var setTypes = descriptor.as(SetTypeDescriptor.class); - return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), id -> + return CodecBuilder.getOrCreateCodec(this, descriptor.getId(), null, (id, metadata) -> new CompilableCodec( id, + metadata, getRelativeCodec.apply(setTypes.typePosition.intValue()), SetCodec::new, t -> Array.newInstance(t, 0).getClass() diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java index e74db216..16699201 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java @@ -2,16 +2,16 @@ import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.builders.CodecBuilder; -import com.edgedb.driver.binary.codecs.ArrayCodec; -import com.edgedb.driver.binary.codecs.Codec; -import com.edgedb.driver.binary.codecs.CompilableCodec; +import com.edgedb.driver.binary.codecs.*; import com.edgedb.driver.binary.protocol.ProtocolProvider; import com.edgedb.driver.binary.protocol.ProtocolVersion; import com.edgedb.driver.binary.protocol.TypeDescriptor; import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; import com.edgedb.driver.binary.protocol.v1.V1ProtocolProvider; +import com.edgedb.driver.binary.protocol.v1.descriptors.SetTypeDescriptor; import com.edgedb.driver.binary.protocol.v2.descriptors.*; import com.edgedb.driver.clients.EdgeDBBinaryClient; +import com.edgedb.driver.datatypes.Range; import com.edgedb.driver.exceptions.MissingCodecException; import com.edgedb.driver.exceptions.UnexpectedMessageException; import org.jetbrains.annotations.Nullable; @@ -92,18 +92,203 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th return CodecBuilder.getOrCreateCodec( this, descriptorInfo.getId(), - id -> new CompilableCodec( + metadata, + (id, meta) -> new CompilableCodec( id, + meta, getRelativeCodec.apply(arrayDescriptor.type.intValue()), ArrayCodec::new, t -> Array.newInstance(t, 0).getClass() ) ); case COMPOUND: + { var compoundDescriptor = descriptorInfo.as(CompoundTypeDescriptor.class); - return + var innerCodecs = new Codec[compoundDescriptor.components.length]; + for(var i = 0; i != compoundDescriptor.components.length; i++) { + innerCodecs[i] = getRelativeCodec.apply(compoundDescriptor.components[i].intValue()); + } + + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + metadata, + (id, meta) -> new CompoundCodec( + id, + meta, + compoundDescriptor.operation, + innerCodecs + ) + ); + } + case ENUMERATION: + var enumerationDescriptor = descriptorInfo.as(EnumerationTypeDescriptor.class); + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + metadata, + (id, meta) -> new EnumerationCodec( + id, + meta, + enumerationDescriptor.members + ) + ); + case INPUT: + var inputDescriptor = descriptorInfo.as(InputShapeDescriptor.class); + + var names = new String[inputDescriptor.elements.length]; + var codecs = new Codec[inputDescriptor.elements.length]; + + for(var i = 0; i != inputDescriptor.elements.length; i++) { + var element = inputDescriptor.elements[i]; + names[i] = element.name; + codecs[i] = getRelativeCodec.apply(element.typePosition.intValue()); + } + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + metadata, + (id, meta) -> new SparseObjectCodec( + id, + meta, + codecs, + names + ) + ); + case NAMED_TUPLE: + { + var namedTupleDescriptor = descriptorInfo.as(NamedTupleTypeDescriptor.class); + + var elements = new ObjectCodec.ObjectProperty[namedTupleDescriptor.elements.length]; + + for(var i = 0; i != namedTupleDescriptor.elements.length; i++) { + var element = namedTupleDescriptor.elements[i]; + elements[i] = new ObjectCodec.ObjectProperty( + element.name, + getRelativeCodec.apply((int)element.typePosition), + null + ); + } + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + metadata, + (id, meta) -> new ObjectCodec( + id, + meta, + elements + ) + ); + } + case OBJECT: + return null; + case OBJECT_OUTPUT: + { + var objectOutputDescriptor = descriptorInfo.as(ObjectOutputShapeDescriptor.class); + var id = objectOutputDescriptor.id; + + if(!objectOutputDescriptor.isEphemeralFreeShape) { + var objectDescriptor = getRelativeDescriptor + .apply(objectOutputDescriptor.type.intValue()) + .as(ObjectTypeDescriptor.class); + + metadata = objectDescriptor.getMetadata(getRelativeCodec, getRelativeDescriptor); + id = objectDescriptor.id; + } + + var elements = new ObjectCodec.ObjectProperty[objectOutputDescriptor.elements.length]; + + for(var i = 0; i != objectOutputDescriptor.elements.length; i++) { + var element = objectOutputDescriptor.elements[i]; + + elements[i] = new ObjectCodec.ObjectProperty( + element.name, + getRelativeCodec.apply(element.typePosition.intValue()), + element.cardinality + ); + } + + return CodecBuilder.getOrCreateCodec( + this, + id, + metadata, + (i, meta) -> new ObjectCodec( + i, + meta, + elements + ) + ); + } + case RANGE: + var rangeDescriptor = descriptorInfo.as(com.edgedb.driver.binary.protocol.v1.descriptors.RangeTypeDescriptor.class); + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + metadata, + (id, meta) -> + new CompilableCodec( + id, + meta, + getRelativeCodec.apply(rangeDescriptor.typePosition.intValue()), + RangeCodec::new, + t -> Range.empty(t).getClass() + ) + ); + case SCALAR: + throw new MissingCodecException( + "Could not find the scalar type " + descriptorInfo.getId().toString() + + ". Please file a bug report with your query that caused this error" + ); + case SET: + var setDescriptor = descriptorInfo.as(SetTypeDescriptor.class); + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + metadata, + (id, meta) -> + new CompilableCodec( + id, + meta, + getRelativeCodec.apply(setDescriptor.typePosition.intValue()), + SetCodec::new, + t -> Array.newInstance(t, 0).getClass() + ) + ); + case TUPLE: + { + var tupleDescriptor = descriptorInfo.as(TupleTypeDescriptor.class); + + var innerCodecs = new Codec[tupleDescriptor.elements.length]; + + for(int i = 0; i != innerCodecs.length; i++) { + innerCodecs[i] = getRelativeCodec.apply(tupleDescriptor.elements[i].intValue()); + } + + return CodecBuilder.getOrCreateCodec( + this, + descriptorInfo.getId(), + metadata, + (id, meta) -> new TupleCodec( + id, + meta, + innerCodecs + ) + ); + } + default: + throw new MissingCodecException( + "Could not find a type descriptor with the type " + + ((DescriptorType) descriptorInfo.type).getValue() + + ". Please file a bug report with your query that caused this error." + ); } } } From 4dd1dd84c6f7fdc0073df7a4513ff30ea84cd87e Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Fri, 28 Jul 2023 15:24:34 -0300 Subject: [PATCH 06/10] v2 protocol tests and fixes --- edgedb.toml | 2 +- .../src/main/resources/logback.xml | 16 ++++++ .../edgedb/driver/binary/PacketReader.java | 52 ++++++++++++------- .../driver/binary/builders/CodecBuilder.java | 30 +++++++++-- .../internal/ObjectEnumeratorImpl.java | 18 +++---- .../builders/types/TypeDeserializerInfo.java | 2 +- .../driver/binary/codecs/ArrayCodec.java | 4 +- .../driver/binary/codecs/ObjectCodec.java | 17 ++++-- .../driver/binary/codecs/RangeCodec.java | 14 ++--- .../edgedb/driver/binary/codecs/SetCodec.java | 26 +++++----- .../binary/codecs/SparseObjectCodec.java | 12 ++--- .../driver/binary/codecs/TupleCodec.java | 12 +++-- .../binary/protocol/ProtocolVersion.java | 2 +- .../common/descriptors/CodecMetadata.java | 8 +++ .../protocol/v1/V1ProtocolProvider.java | 11 ++-- .../protocol/v2/V2ProtocolProvider.java | 24 +++++---- .../descriptors/CompoundTypeDescriptor.java | 2 +- .../v2/descriptors/DescriptorType.java | 2 +- .../descriptors/NamedTupleTypeDescriptor.java | 2 +- .../v2/descriptors/ObjectTypeDescriptor.java | 2 +- ...Descriptor.java => SetTypeDescriptor.java} | 4 +- .../protocol/v2/descriptors/ShapeElement.java | 2 +- 22 files changed, 173 insertions(+), 91 deletions(-) create mode 100644 examples/java-examples/src/main/resources/logback.xml rename src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/{SetDescriptor.java => SetTypeDescriptor.java} (76%) diff --git a/edgedb.toml b/edgedb.toml index 257ffb51..e9ced650 100644 --- a/edgedb.toml +++ b/edgedb.toml @@ -1,2 +1,2 @@ [edgedb] -server-version = "3.0" +server-version = "nightly" diff --git a/examples/java-examples/src/main/resources/logback.xml b/examples/java-examples/src/main/resources/logback.xml new file mode 100644 index 00000000..a6ed88b2 --- /dev/null +++ b/examples/java-examples/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + + + + %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java b/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java index 2aff8caf..29f96ddd 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/PacketReader.java @@ -1,11 +1,9 @@ package com.edgedb.driver.binary; -import com.edgedb.driver.binary.codecs.Codec; -import com.edgedb.driver.binary.codecs.CodecContext; import com.edgedb.driver.binary.protocol.common.Annotation; import com.edgedb.driver.binary.protocol.common.KeyValue; -import com.edgedb.driver.exceptions.EdgeDBException; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joou.UByte; @@ -13,7 +11,6 @@ import org.joou.ULong; import org.joou.UShort; -import javax.naming.OperationNotSupportedException; import java.lang.reflect.Array; import java.nio.charset.StandardCharsets; import java.util.EnumSet; @@ -25,7 +22,21 @@ import static org.joou.Unsigned.*; public class PacketReader { - private final @NotNull ByteBuf buffer; + public static final class ScopedReader extends PacketReader implements AutoCloseable { + public final boolean isNoData; + + public ScopedReader(@Nullable ByteBuf buffer) { + super(buffer == null ? Unpooled.EMPTY_BUFFER : buffer); + isNoData = buffer == null; + } + + @Override + public void close() { + buffer.release(); + } + } + + protected final @NotNull ByteBuf buffer; private static final @NotNull Map, Function> numberReaderMap; private final int initPos; @@ -80,20 +91,6 @@ public boolean isEmpty() { return this.buffer.readableBytes() == 0; } - public @Nullable T deserializeByteArray(@NotNull Codec codec, CodecContext context) throws EdgeDBException, OperationNotSupportedException { - var buff = readByteArray(); - - if(buff == null) { - return null; - } - - try { - return codec.deserialize(new PacketReader(buff), context); - } finally { - buff.release(); - } - } - public byte[] consumeByteArray() { var arr = new byte[this.buffer.readableBytes()]; this.buffer.readBytes(arr); @@ -171,6 +168,23 @@ public short readInt16() { return arr; } + /** + * Reads the {@code length} number of bytes and creates a new {@linkplain ScopedReader} wrapping the bytes. + * @param length The number of bytes to read. + * @return A scoped reader whose close method releases the read bytes. + */ + public ScopedReader scopedSlice(int length) { + return new ScopedReader(readBytes(length)); + } + + /** + * Calls {@code readByteArray()} and creates a new {@linkplain ScopedReader} wrapping the bytes. + * @return A scoped reader whose close method releases the read bytes. + */ + public ScopedReader scopedSlice() { + return new ScopedReader(readByteArray()); + } + public @Nullable ByteBuf readByteArray() { var len = readInt32(); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java index ac89cde0..2150b6d4 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/CodecBuilder.java @@ -66,7 +66,7 @@ private CodecCache(ProtocolVersion version) { } public static @Nullable Codec getCodec(ProtocolProvider provider, UUID id) { var codec = codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new).cache.get(id); - return codec != null ? codec : getScalarCodec(provider, id); + return codec != null ? codec : getCachedOrScalarCodec(provider, id); } public static @NotNull Codec buildCodec(EdgeDBBinaryClient client, @NotNull UUID id, @Nullable ByteBuf buffer) throws EdgeDBException { @@ -96,6 +96,7 @@ private CodecCache(ProtocolVersion version) { public static @NotNull Codec buildCodec(EdgeDBBinaryClient client, @NotNull UUID id, @NotNull PacketReader reader) throws EdgeDBException { try { if(id.equals(NULL_CODEC_ID)) { + logger.debug("Returning null codec"); return getOrCreateCodec(client.getProtocolProvider(), id, NullCodec::new); } @@ -113,6 +114,8 @@ private CodecCache(ProtocolVersion version) { descriptors.add(descriptor); } + logger.debug("Read {} descriptors, totaling {} bytes", descriptors.size(), reader.position()); + var codecs = new ArrayList>(); for(var i = 0; i != descriptors.size(); i++) { @@ -121,26 +124,32 @@ private CodecCache(ProtocolVersion version) { Codec codec = providerCache.cache.get(descriptor.getId());; if(codec != null) { + logger.debug("Using cached codec {} from ID: {}", codec, descriptor.getId()); codecs.add(i, codec); continue; } - codec = getScalarCodec(client.getProtocolProvider(), descriptor.getId()); + codec = getCachedOrScalarCodec(client.getProtocolProvider(), descriptor.getId()); if(codec != null) { + logger.debug("Using cached codec {} from ID: {}", codec, descriptor.getId()); codecs.add(i, codec); continue; } + logger.debug("Calling protocol provider for codec construction, descriptor type: {}", descriptor.type); + codec = client.getProtocolProvider().buildCodec( descriptor, codecs::get, descriptors::get ); + logger.debug("Protocol provider returned {}", codec == null ? "null" : codec); + codecs.add(i, codec); - logger.debug("Codec {} added: {}", i, codec); + logger.debug("Codec {} added: {}, ID: {}", i, codec, descriptor.getId()); } Codec finalCodec = null; @@ -229,12 +238,25 @@ public static Codec getOrCreateCodec( @Nullable CodecMetadata metadata, @NotNull BiFunction> constructor ) { + if(logger.isDebugEnabled()) { + logger.debug( + "cache requested id: {}. exists?: {}, metadata: {}", + id, + codecCaches + .computeIfAbsent(provider.getVersion(), CodecCache::new) + .codecPartsInstanceCache.containsKey(id), + metadata == null + ? "none" + : metadata.toString() + ); + } + return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) .codecPartsInstanceCache.computeIfAbsent(id, i -> constructor.apply(i, metadata)); } @SuppressWarnings("unchecked") - private static @Nullable Codec getScalarCodec(ProtocolProvider provider, UUID id) { + private static @Nullable Codec getCachedOrScalarCodec(ProtocolProvider provider, UUID id) { return (Codec) codecCaches.computeIfAbsent(provider.getVersion(), CodecCache::new) .codecPartsInstanceCache.computeIfAbsent( id, diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/internal/ObjectEnumeratorImpl.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/internal/ObjectEnumeratorImpl.java index 47a7ab3c..d6485995 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/internal/ObjectEnumeratorImpl.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/internal/ObjectEnumeratorImpl.java @@ -51,17 +51,17 @@ public boolean hasRemaining() { var element = codec.elements[position]; - var data = reader.readByteArray(); + try(var elementReader = reader.scopedSlice()) { + if(elementReader.isNoData) { + return new ObjectEnumerator.ObjectElement(element.name, null, element.codec.getConvertingClass()); + } - if(data == null || data.readableBytes() == 0) { - return new ObjectEnumerator.ObjectElement(element.name, null, element.codec.getConvertingClass()); + return new ObjectEnumerator.ObjectElement( + element.name, + element.codec.deserialize(elementReader, context), + element.codec.getConvertingClass() + ); } - - return new ObjectEnumerator.ObjectElement( - element.name, - element.codec.deserialize(new PacketReader(data), context), - element.codec.getConvertingClass() - ); } finally { position++; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java b/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java index 0b68fac6..487247fa 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/builders/types/TypeDeserializerInfo.java @@ -1,8 +1,8 @@ package com.edgedb.driver.binary.builders.types; +import com.edgedb.driver.ObjectEnumerator; import com.edgedb.driver.annotations.*; import com.edgedb.driver.binary.builders.ObjectBuilder; -import com.edgedb.driver.ObjectEnumerator; import com.edgedb.driver.binary.builders.TypeDeserializerFactory; import com.edgedb.driver.binary.builders.internal.ObjectEnumeratorImpl; import com.edgedb.driver.binary.protocol.common.Cardinality; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java index 25fd44cf..8294e378 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ArrayCodec.java @@ -74,7 +74,9 @@ public void serialize(@NotNull PacketWriter writer, T @Nullable [] value, CodecC var array = (T[])Array.newInstance(innerCodec.getConvertingClass(), numElements); for(int i = 0; i != numElements; i++) { - array[i] = reader.deserializeByteArray(innerCodec, context); + try(var elementReader = reader.scopedSlice()) { + array[i] = innerCodec.deserialize(elementReader, context); + } } return array; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java index 638dcb04..3df4929c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/ObjectCodec.java @@ -30,7 +30,7 @@ public static final class TypeInitializedObjectCodec extends ObjectCodec { private final @NotNull ObjectCodec parent; public TypeInitializedObjectCodec(@NotNull Class target, @NotNull ObjectCodec parent) throws EdgeDBException { - super(parent.id, parent.metadata, parent.elements); + super(parent); this.parent = parent; this.target = target; @@ -42,7 +42,7 @@ public TypeInitializedObjectCodec(@NotNull Class target, @NotNull ObjectCodec } public TypeInitializedObjectCodec(@NotNull TypeDeserializerInfo info, @NotNull ObjectCodec parent) { - super(parent.id, parent.metadata, parent.elements); + super(parent); this.parent = parent; this.target = info.getType(); @@ -86,15 +86,24 @@ public ObjectProperty(String name, Codec codec, @Nullable Cardinality cardina } } + public final @Nullable UUID typeId; public final ObjectProperty[] elements; private final @NotNull ConcurrentMap, TypeInitializedObjectCodec> typeCodecs; - public ObjectCodec(UUID id, @Nullable CodecMetadata metadata, ObjectProperty... elements) { - super(id, metadata, Object.class); + public ObjectCodec(UUID shapeId, @Nullable UUID typeId, @Nullable CodecMetadata metadata, ObjectProperty... elements) { + super(shapeId, metadata, Object.class); + this.typeId = typeId; this.elements = elements; this.typeCodecs = new ConcurrentHashMap<>(); } + private ObjectCodec(ObjectCodec other) { + super(other.id, other.metadata, Object.class); + this.typeId = other.typeId; + this.elements = other.elements; + this.typeCodecs = other.typeCodecs; + } + public TypeInitializedObjectCodec getOrCreateTypeCodec(Class cls) throws EdgeDBException { return getOrCreateTypeCodec(cls, t -> new TypeInitializedObjectCodec(t, this)); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java index 19033b5c..6418a22c 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/RangeCodec.java @@ -1,17 +1,15 @@ package com.edgedb.driver.binary.codecs; +import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.binary.PacketWriter; import com.edgedb.driver.binary.codecs.common.RangeFlags; import com.edgedb.driver.binary.protocol.common.descriptors.CodecMetadata; import com.edgedb.driver.datatypes.Range; -import com.edgedb.driver.binary.PacketReader; import com.edgedb.driver.exceptions.EdgeDBException; -import com.edgedb.driver.util.BinaryProtocolUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; - import java.util.EnumSet; import java.util.UUID; @@ -76,13 +74,15 @@ public void serialize(@NotNull PacketWriter writer, @Nullable Range value, Co T lowerBound = null, upperBound = null; if(!flags.contains(RangeFlags.INFINITE_LOWER_BOUNDS)) { - reader.skip(BinaryProtocolUtils.INT_SIZE); - lowerBound = innerCodec.deserialize(reader, context); + try(var elementReader = reader.scopedSlice()) { + lowerBound = innerCodec.deserialize(elementReader, context); + } } if(!flags.contains(RangeFlags.INFINITE_UPPER_BOUNDS)) { - reader.skip(BinaryProtocolUtils.INT_SIZE); - upperBound = innerCodec.deserialize(reader, context); + try(var elementReader = reader.scopedSlice()) { + upperBound = innerCodec.deserialize(elementReader, context); + } } return Range.create( diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java index a1b4b618..77289041 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SetCodec.java @@ -71,27 +71,27 @@ public void serialize(PacketWriter writer, @Nullable Collection value, CodecC } private @Nullable T deserializeEnvelopeElement(@NotNull PacketReader reader, CodecContext context) throws EdgeDBException, OperationNotSupportedException { - reader.skip(INT_SIZE); + try(var elementReader = reader.scopedSlice()) { + var envelopeElements = elementReader.readInt32(); - var envelopeElements = reader.readInt32(); + if(envelopeElements != 1) { + throw new EdgeDBException(String.format("Envelope should contain only one element, but this envelope contains %d", envelopeElements)); + } - if(envelopeElements != 1) { - throw new EdgeDBException(String.format("Envelope should contain only one element, but this envelope contains %d", envelopeElements)); - } - - reader.skip(INT_SIZE); + elementReader.skip(INT_SIZE); - return innerCodec.deserialize(reader, context); + return innerCodec.deserialize(elementReader, context); + } } private @Nullable T deserializeSetElement(@NotNull PacketReader reader, CodecContext context) throws EdgeDBException, OperationNotSupportedException { - var data = reader.readByteArray(); + try(var elementReader = reader.scopedSlice()) { + if(elementReader.isNoData) { + return null; + } - if(data == null) { - return null; + return innerCodec.deserialize(elementReader, context); } - - return innerCodec.deserialize(new PacketReader(data), context); } @FunctionalInterface diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java index 9dfd8239..eb1a9aa3 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/SparseObjectCodec.java @@ -77,14 +77,14 @@ public void serialize(@NotNull PacketWriter writer, @Nullable Map val var index = reader.readInt32(); var elementName = this.propertyNames[index]; - var data = reader.readByteArray(); + try(var elementReader = reader.scopedSlice()) { + if(elementReader.isNoData) { + map.put(elementName, null); + continue; + } - if(data == null) { - map.put(elementName, null); - continue; + map.put(elementName, innerCodecs[i].deserialize(elementReader, context)); } - - map.put(elementName, innerCodecs[i].deserialize(new PacketReader(data), context)); } return map; diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java index 616568a7..551f94ce 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/TupleCodec.java @@ -65,14 +65,16 @@ public void serialize(@NotNull PacketWriter writer, @Nullable Tuple value, Codec reader.skip(INT_SIZE); // reserved - var data = reader.readByteArray(); + try(var elementReader = reader.scopedSlice()) { + if(elementReader.isNoData) { + elements[i] = Tuple.Element.of(null, codec.getConvertingClass()); + continue; + } - if(data == null) { - elements[i] = Tuple.Element.of(null, codec.getConvertingClass()); - continue; + elements[i] = Tuple.Element.of(codec.deserialize(elementReader, context), codec.getConvertingClass()); } - elements[i] = Tuple.Element.of(codec.deserialize(new PacketReader(data), context), codec.getConvertingClass()); + } return Tuple.of(elements); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java index 422baa98..e02f4b35 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/ProtocolVersion.java @@ -8,7 +8,7 @@ import java.util.concurrent.ConcurrentMap; public final class ProtocolVersion { - public static final ProtocolVersion BINARY_PROTOCOL_DEFAULT_VERSION = of(1, 0); + public static final ProtocolVersion BINARY_PROTOCOL_DEFAULT_VERSION = of(2, 0); private static final ConcurrentMap VERSIONS = new ConcurrentHashMap<>() {{ put(keyOf(1, 0), new ProtocolVersion(1, 0)); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java index a53b3ef3..cbebba2f 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/common/descriptors/CodecMetadata.java @@ -16,4 +16,12 @@ public CodecMetadata(String schemaName, boolean isSchemaDefined, CodecAncestor[] this.isSchemaDefined = isSchemaDefined; this.ancestors = ancestors; } + + @Override + public String toString() { + return String.format( + "name: '%s', isSchemaDefined: %s, ancestors: %d", + schemaName, isSchemaDefined, ancestors.length + ); + } } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java index 8c24a8ef..aac835f8 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v1/V1ProtocolProvider.java @@ -208,7 +208,7 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) this, descriptor.getId(), null, - (id, metadata) -> new ObjectCodec(id, metadata, elements) + (id, metadata) -> new ObjectCodec(id, null, metadata, elements) ); } case OBJECT_SHAPE_DESCRIPTOR: @@ -230,7 +230,7 @@ public TypeDescriptorInfo> readDescriptor(PacketReader reader) this, descriptor.getId(), null, - (id, metadata) -> new ObjectCodec(id, metadata, elements) + (id, metadata) -> new ObjectCodec(id, null, metadata, elements) ); } case RANGE_TYPE_DESCRIPTOR: @@ -790,8 +790,11 @@ private void parseServerSettings(@NotNull ParameterStatus status) throws EdgeDBE var codec = CodecBuilder.getCodec(this, descriptorId, Map.class); if(codec == null) { - var descriptorReader = new PacketReader(reader.readBytes(descriptorLength)); - codec = CodecBuilder.buildCodec(client, descriptorId, descriptorReader, Map.class); + try(var descriptorReader = reader.scopedSlice(descriptorLength)) { + codec = CodecBuilder.buildCodec(client, descriptorId, descriptorReader, Map.class); + } + } else { + reader.skip(descriptorLength); } reader.skip(BinaryProtocolUtils.INT_SIZE); // discard length diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java index 16699201..d34b3c93 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java @@ -8,7 +8,6 @@ import com.edgedb.driver.binary.protocol.TypeDescriptor; import com.edgedb.driver.binary.protocol.TypeDescriptorInfo; import com.edgedb.driver.binary.protocol.v1.V1ProtocolProvider; -import com.edgedb.driver.binary.protocol.v1.descriptors.SetTypeDescriptor; import com.edgedb.driver.binary.protocol.v2.descriptors.*; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.datatypes.Range; @@ -41,7 +40,7 @@ public class V2ProtocolProvider extends V1ProtocolProvider implements ProtocolPr put(DescriptorType.OBJECT, ObjectTypeDescriptor::new); put(DescriptorType.RANGE, RangeTypeDescriptor::new); put(DescriptorType.SCALAR, ScalarTypeDescriptor::new); - put(DescriptorType.SET, SetDescriptor::new); + put(DescriptorType.SET, SetTypeDescriptor::new); put(DescriptorType.TUPLE, TupleTypeDescriptor::new); put(DescriptorType.TYPE_ANNOTATION_TEXT, (ignored, reader) -> new TypeAnnotationTextDescriptor(reader)); }}; @@ -58,6 +57,8 @@ public V2ProtocolProvider(EdgeDBBinaryClient client) { @Override public TypeDescriptorInfo readDescriptor(PacketReader reader) throws UnexpectedMessageException { + var length = reader.readUInt32(); + var type = reader.readEnum(DescriptorType.class, Byte.TYPE); var id = type == DescriptorType.TYPE_ANNOTATION_TEXT ? null : reader.readUUID(); @@ -181,6 +182,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th metadata, (id, meta) -> new ObjectCodec( id, + null, meta, elements ) @@ -191,17 +193,20 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th case OBJECT_OUTPUT: { var objectOutputDescriptor = descriptorInfo.as(ObjectOutputShapeDescriptor.class); - var id = objectOutputDescriptor.id; + ObjectTypeDescriptor objectDescriptor = null; if(!objectOutputDescriptor.isEphemeralFreeShape) { - var objectDescriptor = getRelativeDescriptor + objectDescriptor= getRelativeDescriptor .apply(objectOutputDescriptor.type.intValue()) .as(ObjectTypeDescriptor.class); metadata = objectDescriptor.getMetadata(getRelativeCodec, getRelativeDescriptor); - id = objectDescriptor.id; } + final var typeId = objectDescriptor == null + ? null + : objectDescriptor.id; + var elements = new ObjectCodec.ObjectProperty[objectOutputDescriptor.elements.length]; for(var i = 0; i != objectOutputDescriptor.elements.length; i++) { @@ -216,17 +221,18 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th return CodecBuilder.getOrCreateCodec( this, - id, + descriptorInfo.getId(), // use the shapes ID for cache control. metadata, (i, meta) -> new ObjectCodec( i, + typeId, meta, elements ) ); } case RANGE: - var rangeDescriptor = descriptorInfo.as(com.edgedb.driver.binary.protocol.v1.descriptors.RangeTypeDescriptor.class); + var rangeDescriptor = descriptorInfo.as(RangeTypeDescriptor.class); return CodecBuilder.getOrCreateCodec( this, @@ -236,7 +242,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th new CompilableCodec( id, meta, - getRelativeCodec.apply(rangeDescriptor.typePosition.intValue()), + getRelativeCodec.apply(rangeDescriptor.type.intValue()), RangeCodec::new, t -> Range.empty(t).getClass() ) @@ -257,7 +263,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th new CompilableCodec( id, meta, - getRelativeCodec.apply(setDescriptor.typePosition.intValue()), + getRelativeCodec.apply(setDescriptor.type.intValue()), SetCodec::new, t -> Array.newInstance(t, 0).getClass() ) diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java index f44b9a4e..b5fd9863 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/CompoundTypeDescriptor.java @@ -23,7 +23,7 @@ public CompoundTypeDescriptor(UUID id, PacketReader reader) { this.id = id; this.name = reader.readString(); this.isSchemaDefined = reader.readBoolean(); - this.operation = reader.readEnum(TypeOperation.class, Byte.class); + this.operation = reader.readEnum(TypeOperation.class, Byte.TYPE); this.components = reader.readArrayOf(UShort.class, PacketReader::readUInt16, UShort.class); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java index 744f0b77..17cd58a4 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/DescriptorType.java @@ -16,7 +16,7 @@ public enum DescriptorType implements BinaryEnum { COMPOUND(11), TYPE_ANNOTATION_TEXT(127); - private byte value; + private final byte value; DescriptorType(int value) { this.value = (byte)(value & 0xFF); diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java index ac6c3a1a..4b624bf6 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/NamedTupleTypeDescriptor.java @@ -29,7 +29,7 @@ public NamedTupleTypeDescriptor(UUID id, PacketReader reader) { @Override public UUID getId() { - return null; + return this.id; } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java index ce74a7dc..d06b1855 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ObjectTypeDescriptor.java @@ -23,7 +23,7 @@ public ObjectTypeDescriptor(UUID id, PacketReader reader) { @Override public UUID getId() { - return null; + return this.id; } @Override diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetDescriptor.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetTypeDescriptor.java similarity index 76% rename from src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetDescriptor.java rename to src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetTypeDescriptor.java index 91b02c5f..9170ff83 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetDescriptor.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/SetTypeDescriptor.java @@ -6,11 +6,11 @@ import java.util.UUID; -public final class SetDescriptor implements TypeDescriptor { +public final class SetTypeDescriptor implements TypeDescriptor { public final UUID id; public final UShort type; - public SetDescriptor(UUID id, PacketReader reader) { + public SetTypeDescriptor(UUID id, PacketReader reader) { this.id = id; this.type = reader.readUInt16(); } diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java index 98a200f8..879c1ddb 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/descriptors/ShapeElement.java @@ -15,7 +15,7 @@ public final class ShapeElement { public ShapeElement(PacketReader reader) { this.flags = reader.readEnum(ShapeElementFlags.class, UInteger.class); - this.cardinality = reader.readEnum(Cardinality.class, Byte.class); + this.cardinality = reader.readEnum(Cardinality.class, Byte.TYPE); this.name = reader.readString(); this.typePosition = reader.readUInt16(); this.sourceTypePosition = reader.readUInt16(); From e3ef2d652a2fe0e31b57c0e810e54f18ddbccec6 Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Fri, 28 Jul 2023 16:19:02 -0300 Subject: [PATCH 07/10] implement CompoundCodec --- .../driver/binary/codecs/CompoundCodec.java | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java index 9f36bb24..aa124946 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/codecs/CompoundCodec.java @@ -8,11 +8,14 @@ import org.jetbrains.annotations.Nullable; import javax.naming.OperationNotSupportedException; +import java.util.Collection; import java.util.UUID; +import static com.edgedb.driver.util.BinaryProtocolUtils.INT_SIZE; + public class CompoundCodec extends CodecBase { private final TypeOperation operation; - private final Codec[] elements; + private final Codec[] innerCodecs; public CompoundCodec( UUID id, @@ -23,17 +26,69 @@ public CompoundCodec( super(id, metadata, Object.class); this.operation = operation; - this.elements = elements; + this.innerCodecs = elements; + } + + public TypeOperation getTypeOperation() { + return this.operation; } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public void serialize(PacketWriter writer, @Nullable Object value, CodecContext context) throws OperationNotSupportedException, EdgeDBException { - throw new OperationNotSupportedException("No data wire format has been defined for this type of codec"); + if(value == null) { + writer.write(-1); + return; + } + + if(!(value instanceof Collection)) { + throw new IllegalArgumentException("The provided argument was not a collection"); + } + + + var collection = ((Collection)value).toArray(); + + writer.write(collection.length); + + var visitor = context.getTypeVisitor(); + + for(int i = 0; i != collection.length; i++) { + writer.write(0); // reserved + + var elementValue = collection[i]; + + if(elementValue == null) { + writer.write(-1); + continue; + } + + visitor.setTargetType(elementValue.getClass()); + Codec codec = visitor.visit(this.innerCodecs[i]); + visitor.reset(); + + writer.writeDelegateWithLength((v) -> codec.serialize(v, elementValue, context)); + } } @Nullable @Override public Object deserialize(PacketReader reader, CodecContext context) throws EdgeDBException, OperationNotSupportedException { - throw new OperationNotSupportedException("No data wire format has been defined for this type of codec"); + var numElements = reader.readInt32(); + + if(numElements != this.innerCodecs.length) { + throw new EdgeDBException("Expected " + this.innerCodecs.length + " elements, but got " + numElements); + } + + var elements = new Object[numElements]; + + for(var i = 0; i != numElements; i++) { + reader.skip(INT_SIZE); + + try(var elementReader = reader.scopedSlice()) { + elements[i] = innerCodecs[i].deserialize(elementReader, context); + } + } + + return elements; } } From 84c5b5da49fe9ffb8ca77923788d3e401bbc43ab Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Fri, 28 Jul 2023 16:27:38 -0300 Subject: [PATCH 08/10] go back to EdgeDB 3.x --- edgedb.toml | 2 +- .../java/com/edgedb/driver/clients/EdgeDBBinaryClient.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/edgedb.toml b/edgedb.toml index e9ced650..257ffb51 100644 --- a/edgedb.toml +++ b/edgedb.toml @@ -1,2 +1,2 @@ [edgedb] -server-version = "nightly" +server-version = "3.0" diff --git a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java index c107f514..b0ec182f 100644 --- a/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java +++ b/src/driver/src/main/java/com/edgedb/driver/clients/EdgeDBBinaryClient.java @@ -404,14 +404,16 @@ public ByteBuf serializeState() throws OperationNotSupportedException, EdgeDBExc } public boolean tryNegotiateProtocol(UShort major, UShort minor) { - logger.info("Server requested protocol {}.{}, current: {}", major, major, protocolProvider.getVersion()); + logger.info("Server requested protocol {}.{}, current: {}", major, minor, protocolProvider.getVersion()); var newProvider = ProtocolProvider.PROVIDERS.get(ProtocolVersion.of(major, minor)); if(newProvider != null) { this.protocolProvider = newProvider.apply(this); + logger.debug("Protocol provider found, using {}", this.protocolProvider); ProtocolProvider.updateProviderFor(this, this.protocolProvider); return true; } + logger.debug("No provider found for {}.{}", major, minor); return false; } From dbd4099290d12ab69e87c6d402f354b064c228a7 Mon Sep 17 00:00:00 2001 From: Quin Lynch <49576606+quinchs@users.noreply.github.com> Date: Sat, 29 Jul 2023 00:33:23 -0300 Subject: [PATCH 09/10] fix error message version type --- .../edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java index d34b3c93..efcbc3d3 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/protocol/v2/V2ProtocolProvider.java @@ -79,7 +79,7 @@ public TypeDescriptorInfo readDescriptor(PacketReader reader) th Function> getRelativeDescriptor ) throws MissingCodecException { if(!(descriptorInfo.type instanceof DescriptorType)) { - throw new IllegalArgumentException("Expected v1 descriptor type, got " + descriptorInfo.type.getClass().getName()); + throw new IllegalArgumentException("Expected v2 descriptor type, got " + descriptorInfo.type.getClass().getName()); } var metadata = descriptorInfo.descriptor instanceof MetadataDescriptor From 8c07ee464c3d1822db78ba0a86081cc673afd34f Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Wed, 25 Oct 2023 14:27:48 -0300 Subject: [PATCH 10/10] Update ChannelDuplexer.java --- .../driver/binary/duplexers/ChannelDuplexer.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java index 7879d679..638cb82d 100644 --- a/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java +++ b/src/driver/src/main/java/com/edgedb/driver/binary/duplexers/ChannelDuplexer.java @@ -2,10 +2,10 @@ import com.edgedb.driver.ErrorCode; import com.edgedb.driver.async.ChannelCompletableFuture; -import com.edgedb.driver.binary.packets.receivable.ErrorResponse; -import com.edgedb.driver.binary.packets.receivable.Receivable; -import com.edgedb.driver.binary.packets.sendables.Sendable; -import com.edgedb.driver.binary.packets.sendables.Terminate; +import com.edgedb.driver.binary.protocol.ProtocolProvider; +import com.edgedb.driver.binary.protocol.Receivable; +import com.edgedb.driver.binary.protocol.Sendable; +import com.edgedb.driver.binary.protocol.common.ProtocolError; import com.edgedb.driver.clients.EdgeDBBinaryClient; import com.edgedb.driver.exceptions.ConnectionFailedException; import com.edgedb.driver.exceptions.ConnectionFailedTemporarilyException; @@ -96,9 +96,9 @@ public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) var protocolMessage = (Receivable)msg; if( - protocolMessage instanceof ErrorResponse && ( - ((ErrorResponse)protocolMessage).errorCode == ErrorCode.IDLE_SESSION_TIMEOUT_ERROR || - ((ErrorResponse)protocolMessage).errorCode == ErrorCode.IDLE_TRANSACTION_TIMEOUT_ERROR + protocolMessage instanceof ProtocolError && ( + ((ProtocolError)protocolMessage).getErrorCode() == ErrorCode.IDLE_SESSION_TIMEOUT_ERROR || + ((ProtocolError)protocolMessage).getErrorCode() == ErrorCode.IDLE_TRANSACTION_TIMEOUT_ERROR ) ) { logger.debug("Got idle disconnect message, marking as closed"); @@ -365,7 +365,7 @@ public CompletionStage disconnect() { if(this.isConnected) { logger.debug("Sending terminate for disconnect"); - return send(new Terminate()) + return send(getProtocolProvider().terminate()) .thenCompose(v -> ChannelCompletableFuture.completeFrom(this.channel.disconnect())); }