From 8e7a9b82f4d29e99d2c1c741502000b18e9d3a56 Mon Sep 17 00:00:00 2001 From: Florian Hockmann Date: Wed, 8 Dec 2021 15:19:16 +0100 Subject: [PATCH] Add basic GraphBinary support Only RelationIdentifier and Text predicates are supported right now. Geoshapes need to wait for JanusGraph 1.0.0 because of JanusGraph/janusgraph#2856. I also changed the API of the JanusGraphClientBuilder a bit to be more independent of GraphSON and to be more in line with Gremlin.NET. It now simply takes an `IMessageSerializer`. GraphSON now uses JanusGraph predicates by default. So, users need to change that on their own if they want to connect with a JanusGraph Server < 0.6.0. That should be OK however given that this contribution includes breaking changes any way and it makes it easier to remove this functionality in an upcoming version completely. This also includes an update of Gremlin.Net to 3.5.2 as we need TINKERPOP-2646[1] for this change. Fixes #82 [1]: https://issues.apache.org/jira/browse/TINKERPOP-2646 Signed-off-by: Florian Hockmann --- README.md | 37 +++++- .../JanusGraphTypeSerializerRegistry.cs | 70 ++++++++++ .../IO/GraphBinary/Types/GraphBinaryType.cs | 55 ++++++++ .../Types/JanusGraphPSerializer.cs | 47 +++++++ .../Types/JanusGraphTypeSerializer.cs | 123 ++++++++++++++++++ .../Types/RelationIdentifierSerializer.cs | 52 ++++++++ .../JanusGraphGraphSONMessageSerializer.cs | 80 ++++++++++++ .../IO/GraphSON/JanusGraphSONWriterBuilder.cs | 2 +- .../GraphSON/RelationIdentifierSerializer.cs | 2 +- src/JanusGraph.Net/JanusGraph.Net.csproj | 4 +- src/JanusGraph.Net/JanusGraphClientBuilder.cs | 21 ++- src/JanusGraph.Net/RelationIdentifier.cs | 74 ++++++++++- src/JanusGraph.Net/Utils/LongEncoding.cs | 63 +++++++++ .../DocTraversalsTests.cs | 22 ++-- .../GraphBinaryDocTraversalsTests.cs | 51 ++++++++ .../GraphBinaryTextTests.cs | 38 ++++++ .../GraphSONTextTests.cs | 36 +++++ .../GeoshapeDeserializerTests.cs | 17 +-- .../{GraphSON => }/GeoshapeSerializerTests.cs | 17 +-- ...naryRelationIdentifierDeserializerTests.cs | 38 ++++++ ...BinaryRelationIdentifierSerializerTests.cs | 38 ++++++ .../GraphSONGeoshapeDeserializerTests.cs | 35 +++++ .../GraphSONGeoshapeSerializerTests.cs | 35 +++++ ...hSONRelationIdentifierDeserializerTests.cs | 35 +++++ ...aphSONRelationIdentifierSerializerTests.cs | 35 +++++ .../RelationIdentifierDeserializerTests.cs | 19 +-- .../RelationIdentifierSerializerTests.cs | 19 +-- .../RemoteConnectionFactory.cs | 12 +- .../TextTests.cs | 26 ++-- ...nIdentifierSerializationSymmetricyTests.cs | 2 +- .../RelationIdentifierTests.cs | 20 +++ 31 files changed, 1028 insertions(+), 97 deletions(-) create mode 100644 src/JanusGraph.Net/IO/GraphBinary/JanusGraphTypeSerializerRegistry.cs create mode 100644 src/JanusGraph.Net/IO/GraphBinary/Types/GraphBinaryType.cs create mode 100644 src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphPSerializer.cs create mode 100644 src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphTypeSerializer.cs create mode 100644 src/JanusGraph.Net/IO/GraphBinary/Types/RelationIdentifierSerializer.cs create mode 100644 src/JanusGraph.Net/IO/GraphSON/JanusGraphGraphSONMessageSerializer.cs create mode 100644 src/JanusGraph.Net/Utils/LongEncoding.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/GraphBinaryDocTraversalsTests.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/GraphBinaryTextTests.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/GraphSONTextTests.cs rename test/JanusGraph.Net.IntegrationTest/IO/{GraphSON => }/GeoshapeDeserializerTests.cs (71%) rename test/JanusGraph.Net.IntegrationTest/IO/{GraphSON => }/GeoshapeSerializerTests.cs (69%) create mode 100644 test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierDeserializerTests.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierSerializerTests.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeDeserializerTests.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeSerializerTests.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierDeserializerTests.cs create mode 100644 test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierSerializerTests.cs rename test/JanusGraph.Net.IntegrationTest/IO/{GraphSON => }/RelationIdentifierDeserializerTests.cs (69%) rename test/JanusGraph.Net.IntegrationTest/IO/{GraphSON => }/RelationIdentifierSerializerTests.cs (68%) diff --git a/README.md b/README.md index 87446fe..91fa5ee 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ await g.V().Has("demigod", "name", "hercules").OutE("battled") .Has("place", Geoshape.Point(38.1f, 23.7f)).Count().Promise(t => t.Next()); ``` -Only the point Geoshape is supported right now. +Only the `Point` Geoshape is supported right now. ## Version Compatibility @@ -78,11 +78,12 @@ The lowest supported JanusGraph version is 0.3.0. The following table shows the supported JanusGraph versions for each version of JanusGraph.Net: -| JanusGraph.Net | JanusGraph | -|---|---| -| 0.1.z | 0.3.z | -| 0.2.z | 0.4.z, 0.5.z | -| 0.3.z | 0.4.z, 0.5.z, 0.6.z | +| JanusGraph.Net | JanusGraph | +| -------------- | ---------------------- | +| 0.1.z | 0.3.z | +| 0.2.z | 0.4.z, 0.5.z | +| 0.3.z | 0.4.z, 0.5.z, 0.6.z | +| 0.4.z | (0.4.z, 0.5.z,)* 0.6.z | While it should also be possible to use JanusGraph.Net with other versions of JanusGraph than mentioned here, compatibility is not tested and some @@ -90,6 +91,30 @@ functionality (like added Gremlin steps) will not work as it is not supported yet in case of an older JanusGraph version or was removed in a newer JanusGraph version. +\* JanusGraph.Net 0.4 still supports older versions of JanusGraph, but the +`janusGraphPredicates` flag needs to be set to `false` in order to be able to +use JanusGraph's Text predicates. + +## Serialization Formats + +JanusGraph.Net supports GraphSON 3 as well as GraphBinary. GraphSON 3 is used +by default. GraphBinary can be configured like this: + +```c# +var client = JanusGraphClientBuilder.BuildClientForServer(new GremlinServer("localhost", 8182)) + .WithSerializer(new GraphBinaryMessageSerializer(JanusGraphTypeSerializerRegistry.Instance)).Create(); +``` + +Note that support for GraphBinary was only added in JanusGraph 0.6.0. So, the +server needs to be at least on that version. + +Not all of the JanusGraph-specific types are already supported by both formats: + +| Format | RelationIdentifier | Text predicates | Geoshapes | Geo predicates | +| ----------- | ------------------ | --------------- | --------- | -------------- | +| GraphSON3 | x | x | `Point` | - | +| GraphBinary | x | x | - | - | + ## Community JanusGraph.Net uses the same communication channels as JanusGraph in general. diff --git a/src/JanusGraph.Net/IO/GraphBinary/JanusGraphTypeSerializerRegistry.cs b/src/JanusGraph.Net/IO/GraphBinary/JanusGraphTypeSerializerRegistry.cs new file mode 100644 index 0000000..5fb1e34 --- /dev/null +++ b/src/JanusGraph.Net/IO/GraphBinary/JanusGraphTypeSerializerRegistry.cs @@ -0,0 +1,70 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; +using Gremlin.Net.Structure.IO.GraphBinary; +using Gremlin.Net.Structure.IO.GraphBinary.Types; +using JanusGraph.Net.IO.GraphBinary.Types; + +namespace JanusGraph.Net.IO.GraphBinary +{ + /// + /// Provides GraphBinary serializers for different types, including JanusGraph specific types. + /// + public static class JanusGraphTypeSerializerRegistry + { + /// + /// Provides a default instance with JanusGraph types already registered. + /// + public static readonly TypeSerializerRegistry Instance = Build().Create(); + + private static Builder Build() => new Builder(); + + /// + /// Builds a with serializers for JanusGraph types already registered. + /// + public class Builder + { + private readonly TypeSerializerRegistry.Builder _builder = TypeSerializerRegistry.Build(); + + internal Builder() + { + _builder.AddCustomType(typeof(RelationIdentifier), new RelationIdentifierSerializer()); + _builder.AddCustomType(typeof(JanusGraphP), new JanusGraphPSerializer()); + } + + /// + /// Adds a serializer for a custom type. + /// + /// The custom type supported by the serializer. + /// The serializer for the custom type. + public Builder AddCustomType(Type type, CustomTypeSerializer serializer) + { + _builder.AddCustomType(type, serializer); + return this; + } + + /// + /// Creates the . + /// + public TypeSerializerRegistry Create() => _builder.Create(); + } + } +} \ No newline at end of file diff --git a/src/JanusGraph.Net/IO/GraphBinary/Types/GraphBinaryType.cs b/src/JanusGraph.Net/IO/GraphBinary/Types/GraphBinaryType.cs new file mode 100644 index 0000000..8f69a05 --- /dev/null +++ b/src/JanusGraph.Net/IO/GraphBinary/Types/GraphBinaryType.cs @@ -0,0 +1,55 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +namespace JanusGraph.Net.IO.GraphBinary.Types +{ + /// + /// Represents a JanusGraph GraphBinary type with its type information needed for serialization. + /// + public class GraphBinaryType + { + internal static readonly GraphBinaryType RelationIdentifier = + new GraphBinaryType(0x1001, "janusgraph.RelationIdentifier"); + + internal static readonly GraphBinaryType JanusGraphP = + new GraphBinaryType(0x1002, "janusgraph.P"); + + /// + /// Initializes a new instance of the class. + /// + /// The JanusGraph internal id of the type. + /// The name of the type. + public GraphBinaryType(int typeId, string typeName) + { + TypeId = typeId; + TypeName = typeName; + } + + /// + /// Gets the JanusGraph internal id of the type. + /// + public int TypeId { get; } + + /// + /// Gets the name of the type. + /// + public string TypeName { get; } + } +} \ No newline at end of file diff --git a/src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphPSerializer.cs b/src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphPSerializer.cs new file mode 100644 index 0000000..1bdecb0 --- /dev/null +++ b/src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphPSerializer.cs @@ -0,0 +1,47 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System.IO; +using System.Threading.Tasks; +using Gremlin.Net.Structure.IO.GraphBinary; + +namespace JanusGraph.Net.IO.GraphBinary.Types +{ + internal class JanusGraphPSerializer : JanusGraphTypeSerializer + { + public JanusGraphPSerializer() : base(GraphBinaryType.JanusGraphP) + { + } + + protected override async Task WriteNonNullableValueAsync(JanusGraphP value, Stream stream, + GraphBinaryWriter writer) + { + await writer.WriteValueAsync(value.OperatorName, stream, false).ConfigureAwait(false); + await writer.WriteAsync(value.Value, stream).ConfigureAwait(false); + } + + protected override async Task ReadNonNullableValueAsync(Stream stream, GraphBinaryReader reader) + { + var operatorName = (string)await reader.ReadValueAsync(stream, false).ConfigureAwait(false); + var value = await reader.ReadAsync(stream).ConfigureAwait(false); + return new JanusGraphP(operatorName, value); + } + } +} \ No newline at end of file diff --git a/src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphTypeSerializer.cs b/src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphTypeSerializer.cs new file mode 100644 index 0000000..5ca3688 --- /dev/null +++ b/src/JanusGraph.Net/IO/GraphBinary/Types/JanusGraphTypeSerializer.cs @@ -0,0 +1,123 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System.IO; +using System.Threading.Tasks; +using Gremlin.Net.Structure.IO.GraphBinary; +using Gremlin.Net.Structure.IO.GraphBinary.Types; + +namespace JanusGraph.Net.IO.GraphBinary.Types +{ + /// + /// Base class for GraphBinary serializers of JanusGraph types. + /// + /// The JanusGraph type to be serialized. + public abstract class JanusGraphTypeSerializer : CustomTypeSerializer + { + private readonly GraphBinaryType _type; + + /// + /// Initializes a new instance of the class. + /// + /// The GraphBinaryType for this serializer. + protected JanusGraphTypeSerializer(GraphBinaryType type) + { + _type = type; + } + + /// + public override async Task WriteAsync(object value, Stream stream, GraphBinaryWriter writer) + { + await stream.WriteIntAsync(_type.TypeId).ConfigureAwait(false); + + await WriteValueAsync(value, stream, writer, true).ConfigureAwait(false); + } + + /// + public override async Task WriteValueAsync(object value, Stream stream, GraphBinaryWriter writer, bool nullable) + { + if (value == null) + { + if (!nullable) + { + throw new IOException("Unexpected null value when nullable is false"); + } + + await writer.WriteValueFlagNullAsync(stream).ConfigureAwait(false); + return; + } + + if (nullable) + { + await writer.WriteValueFlagNoneAsync(stream).ConfigureAwait(false); + } + + await WriteNonNullableValueAsync((T) value, stream, writer).ConfigureAwait(false); + } + + /// + /// Writes a non-nullable value without including type information. + /// + /// The value to write. + /// The stream to write to. + /// A that can be used to write nested values. + /// A task that represents the asynchronous write operation. + protected abstract Task WriteNonNullableValueAsync(T value, Stream stream, GraphBinaryWriter writer); + + /// + public override async Task ReadAsync(Stream stream, GraphBinaryReader reader) + { + var customTypeInfo = await stream.ReadIntAsync().ConfigureAwait(false); + if (customTypeInfo != _type.TypeId) + { + throw new IOException( + $"Custom type info {customTypeInfo} doesn't match expected type info {_type.TypeId}"); + } + + return await ReadValueAsync(stream, reader, true).ConfigureAwait(false); + } + + /// + public override async Task ReadValueAsync(Stream stream, GraphBinaryReader reader, bool nullable) + { + if (nullable) + { + var valueFlag = await stream.ReadByteAsync().ConfigureAwait(false); + if ((valueFlag & 1) == 1) + { + return null; + } + } + + return await ReadNonNullableValueAsync(stream, reader).ConfigureAwait(false); + } + + /// + /// Reads a non-nullable value from the stream. + /// + /// The GraphBinary data to parse. + /// A that can be used to read nested values. + /// The read value. + protected abstract Task ReadNonNullableValueAsync(Stream stream, GraphBinaryReader reader); + + /// + public override string TypeName => _type.TypeName; + } +} \ No newline at end of file diff --git a/src/JanusGraph.Net/IO/GraphBinary/Types/RelationIdentifierSerializer.cs b/src/JanusGraph.Net/IO/GraphBinary/Types/RelationIdentifierSerializer.cs new file mode 100644 index 0000000..d1187a3 --- /dev/null +++ b/src/JanusGraph.Net/IO/GraphBinary/Types/RelationIdentifierSerializer.cs @@ -0,0 +1,52 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System.IO; +using System.Threading.Tasks; +using Gremlin.Net.Structure.IO.GraphBinary; + +namespace JanusGraph.Net.IO.GraphBinary.Types +{ + internal class RelationIdentifierSerializer : JanusGraphTypeSerializer + { + public RelationIdentifierSerializer() : base(GraphBinaryType.RelationIdentifier) + { + } + + protected override async Task WriteNonNullableValueAsync(RelationIdentifier value, Stream stream, + GraphBinaryWriter writer) + { + await stream.WriteLongAsync(value.OutVertexId).ConfigureAwait(false); + await stream.WriteLongAsync(value.TypeId).ConfigureAwait(false); + await stream.WriteLongAsync(value.RelationId).ConfigureAwait(false); + await stream.WriteLongAsync(value.InVertexId).ConfigureAwait(false); + } + + protected override async Task ReadNonNullableValueAsync(Stream stream, + GraphBinaryReader reader) + { + var outVertexId = await stream.ReadLongAsync().ConfigureAwait(false); + var typeId = await stream.ReadLongAsync().ConfigureAwait(false); + var relationId = await stream.ReadLongAsync().ConfigureAwait(false); + var inVertexId = await stream.ReadLongAsync().ConfigureAwait(false); + return new RelationIdentifier(outVertexId, typeId, relationId, inVertexId); + } + } +} \ No newline at end of file diff --git a/src/JanusGraph.Net/IO/GraphSON/JanusGraphGraphSONMessageSerializer.cs b/src/JanusGraph.Net/IO/GraphSON/JanusGraphGraphSONMessageSerializer.cs new file mode 100644 index 0000000..cf25d2e --- /dev/null +++ b/src/JanusGraph.Net/IO/GraphSON/JanusGraphGraphSONMessageSerializer.cs @@ -0,0 +1,80 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System.Collections.Generic; +using System.Threading.Tasks; +using Gremlin.Net.Driver; +using Gremlin.Net.Driver.Messages; +using Gremlin.Net.Structure.IO.GraphSON; + +namespace JanusGraph.Net.IO.GraphSON +{ + /// + /// Serializes data to and from JanusGraph Server in GraphSON3 format. + /// + public class JanusGraphGraphSONMessageSerializer : IMessageSerializer + { + private readonly GraphSON3MessageSerializer _serializer; + + /// + /// Initializes a new instance of the class. + /// + /// The used to deserialize from GraphSON. + /// The used to serialize to GraphSON. + public JanusGraphGraphSONMessageSerializer(GraphSON3Reader graphSONReader, GraphSON3Writer graphSONWriter) + { + _serializer = new GraphSON3MessageSerializer(graphSONReader, graphSONWriter); + } + + /// + /// Initializes a new instance of the class. + /// + public JanusGraphGraphSONMessageSerializer() + : this(JanusGraphSONReaderBuilder.Build().Create(), JanusGraphSONWriterBuilder.Build().Create()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// This value activates support for JanusGraph predicate serialization added in + /// JanusGraph 0.6.0. It should be set to true for JanusGraph Server versions >= 0.6.0 and to false for versions before + /// 0.6.0. + /// + public JanusGraphGraphSONMessageSerializer(bool janusGraphPredicates) + : this(JanusGraphSONReaderBuilder.Build().Create(), + JanusGraphSONWriterBuilder.Build(janusGraphPredicates).Create()) + { + } + + /// + public async Task SerializeMessageAsync(RequestMessage requestMessage) + { + return await _serializer.SerializeMessageAsync(requestMessage).ConfigureAwait(false); + } + + /// + public async Task>> DeserializeMessageAsync(byte[] message) + { + return await _serializer.DeserializeMessageAsync(message).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/JanusGraph.Net/IO/GraphSON/JanusGraphSONWriterBuilder.cs b/src/JanusGraph.Net/IO/GraphSON/JanusGraphSONWriterBuilder.cs index d76be2f..a35f0f0 100644 --- a/src/JanusGraph.Net/IO/GraphSON/JanusGraphSONWriterBuilder.cs +++ b/src/JanusGraph.Net/IO/GraphSON/JanusGraphSONWriterBuilder.cs @@ -51,7 +51,7 @@ private JanusGraphSONWriterBuilder(bool janusGraphPredicates) /// public static JanusGraphSONWriterBuilder Build() { - return new JanusGraphSONWriterBuilder(false); + return new JanusGraphSONWriterBuilder(true); } /// diff --git a/src/JanusGraph.Net/IO/GraphSON/RelationIdentifierSerializer.cs b/src/JanusGraph.Net/IO/GraphSON/RelationIdentifierSerializer.cs index 02c05ec..4b3488f 100644 --- a/src/JanusGraph.Net/IO/GraphSON/RelationIdentifierSerializer.cs +++ b/src/JanusGraph.Net/IO/GraphSON/RelationIdentifierSerializer.cs @@ -33,7 +33,7 @@ public Dictionary Dictify(dynamic objectData, GraphSONWriter wr private static Dictionary ValueDict(RelationIdentifier relationIdentifier) { - return new Dictionary {{"relationId", relationIdentifier.RelationId}}; + return new Dictionary {{"relationId", relationIdentifier.StringRepresentation}}; } } } \ No newline at end of file diff --git a/src/JanusGraph.Net/JanusGraph.Net.csproj b/src/JanusGraph.Net/JanusGraph.Net.csproj index 074011f..f318091 100644 --- a/src/JanusGraph.Net/JanusGraph.Net.csproj +++ b/src/JanusGraph.Net/JanusGraph.Net.csproj @@ -25,9 +25,9 @@ - + - + \ No newline at end of file diff --git a/src/JanusGraph.Net/JanusGraphClientBuilder.cs b/src/JanusGraph.Net/JanusGraphClientBuilder.cs index d47e3ca..248ee4d 100644 --- a/src/JanusGraph.Net/JanusGraphClientBuilder.cs +++ b/src/JanusGraph.Net/JanusGraphClientBuilder.cs @@ -33,6 +33,7 @@ public class JanusGraphClientBuilder private readonly GremlinServer _server; private readonly JanusGraphSONReaderBuilder _readerBuilder = JanusGraphSONReaderBuilder.Build(); private readonly JanusGraphSONWriterBuilder _writerBuilder; + private IMessageSerializer _serializer; private ConnectionPoolSettings _connectionPoolSettings; private JanusGraphClientBuilder(GremlinServer server, bool janusGraphPredicates) @@ -47,7 +48,7 @@ private JanusGraphClientBuilder(GremlinServer server, bool janusGraphPredicates) /// The requests should be sent to. public static JanusGraphClientBuilder BuildClientForServer(GremlinServer server) { - return new JanusGraphClientBuilder(server, false); + return new JanusGraphClientBuilder(server, true); } /// @@ -63,11 +64,22 @@ public static JanusGraphClientBuilder BuildClientForServer(GremlinServer server, return new JanusGraphClientBuilder(server, janusGraphPredicates); } + /// + /// Registers a used to serialize data to and from JanusGraph Server. + /// + /// The serializer to use. + public JanusGraphClientBuilder WithSerializer(IMessageSerializer serializer) + { + _serializer = serializer; + return this; + } + /// /// Registers a custom GraphSON deserializer for the given GraphSON type. /// /// The GraphSON type the deserializer should be registered for. /// The deserializer to register. + [Obsolete("Use WithSerializer() instead")] public JanusGraphClientBuilder RegisterDeserializer(string graphSONType, IGraphSONDeserializer deserializer) { _readerBuilder.RegisterDeserializer(graphSONType, deserializer); @@ -79,6 +91,7 @@ public JanusGraphClientBuilder RegisterDeserializer(string graphSONType, IGraphS /// /// The type the serializer should be registered for. /// The serializer to register. + [Obsolete("Use WithSerializer() instead")] public JanusGraphClientBuilder RegisterSerializer(Type type, IGraphSONSerializer serializer) { _writerBuilder.RegisterSerializer(type, serializer); @@ -100,9 +113,9 @@ public JanusGraphClientBuilder WithConnectionPoolSettings(ConnectionPoolSettings /// public IGremlinClient Create() { - return new GremlinClient(_server, - new GraphSON3MessageSerializer(_readerBuilder.Create(), _writerBuilder.Create()), - _connectionPoolSettings); + var serializer = _serializer ?? + new JanusGraphGraphSONMessageSerializer(_readerBuilder.Create(), _writerBuilder.Create()); + return new GremlinClient(_server, serializer, _connectionPoolSettings); } } } \ No newline at end of file diff --git a/src/JanusGraph.Net/RelationIdentifier.cs b/src/JanusGraph.Net/RelationIdentifier.cs index 2d6a203..b026028 100644 --- a/src/JanusGraph.Net/RelationIdentifier.cs +++ b/src/JanusGraph.Net/RelationIdentifier.cs @@ -19,6 +19,8 @@ #endregion using System; +using System.Text; +using JanusGraph.Net.Utils; namespace JanusGraph.Net { @@ -27,26 +29,84 @@ namespace JanusGraph.Net /// public class RelationIdentifier : IEquatable { + private const char ToStringDelimiter = '-'; + /// /// Initializes a new instance of the class. /// - /// The underlying relation id. - public RelationIdentifier(string relationId) + /// The underlying relation id. + public RelationIdentifier(string stringRepresentation) { + StringRepresentation = stringRepresentation; + + var elements = stringRepresentation.Split(ToStringDelimiter); + if (elements.Length != 3 && elements.Length != 4) + throw new ArgumentException($"Not a valid relation identifier: {stringRepresentation}"); + OutVertexId = LongEncoding.Decode(elements[1]); + TypeId = LongEncoding.Decode(elements[2]); + RelationId = LongEncoding.Decode(elements[0]); + if (elements.Length == 4) + { + InVertexId = LongEncoding.Decode(elements[3]); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + public RelationIdentifier(long outVertexId, long typeId, long relationId, long inVertexId) + { + OutVertexId = outVertexId; + TypeId = typeId; RelationId = relationId; + InVertexId = inVertexId; + + var sb = new StringBuilder(); + sb.Append(LongEncoding.Encode(relationId)).Append(ToStringDelimiter) + .Append(LongEncoding.Encode(outVertexId)).Append(ToStringDelimiter).Append(LongEncoding.Encode(typeId)); + if (inVertexId != 0) + { + sb.Append(ToStringDelimiter).Append(LongEncoding.Encode(inVertexId)); + } + + StringRepresentation = sb.ToString(); } /// - /// Gets the underlying relation id. + /// Gets the string representation of this . + /// + public string StringRepresentation { get; } + + /// + /// Gets the id of the outgoing vertex. + /// + public long OutVertexId { get; } + + /// + /// Gets the JanusGraph internal type id. + /// + public long TypeId { get; } + + /// + /// Gets the JanusGraph internal relation id. + /// + public long RelationId { get; } + + /// + /// Gets the id of the incoming vertex. /// - public string RelationId { get; } + public long InVertexId { get; } /// public bool Equals(RelationIdentifier other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return string.Equals(RelationId, other.RelationId); + return string.Equals(StringRepresentation, other.StringRepresentation); } /// @@ -61,13 +121,13 @@ public override bool Equals(object obj) /// public override int GetHashCode() { - return RelationId != null ? RelationId.GetHashCode() : 0; + return StringRepresentation != null ? StringRepresentation.GetHashCode() : 0; } /// public override string ToString() { - return RelationId; + return StringRepresentation; } } } \ No newline at end of file diff --git a/src/JanusGraph.Net/Utils/LongEncoding.cs b/src/JanusGraph.Net/Utils/LongEncoding.cs new file mode 100644 index 0000000..d82e31e --- /dev/null +++ b/src/JanusGraph.Net/Utils/LongEncoding.cs @@ -0,0 +1,63 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; +using System.Text; + +namespace JanusGraph.Net.Utils +{ + /// + /// Utility class for encoding longs in strings, re-implemented from its Java equivalent. + /// + internal static class LongEncoding + { + private const string BaseSymbols = "0123456789abcdefghijklmnopqrstuvwxyz"; + private static readonly int NrSymbols = BaseSymbols.Length; + + public static long Decode(string s) + { + long num = 0; + foreach (var ch in s) + { + num *= NrSymbols; + var pos = BaseSymbols.IndexOf(ch); + if (pos < 0) + throw new ArgumentException($"Symbol {ch} not allowed, only these symbols are: {BaseSymbols}"); + num += pos; + } + + return num; + } + + public static string Encode(long num) + { + var sb = new StringBuilder(); + while (num != 0) + { + sb.Append(BaseSymbols[(int)num % NrSymbols]); + num /= NrSymbols; + } + + var chars = sb.ToString().ToCharArray(); + Array.Reverse(chars); + return new string(chars); + } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/DocTraversalsTests.cs b/test/JanusGraph.Net.IntegrationTest/DocTraversalsTests.cs index bc6679b..9ff7899 100644 --- a/test/JanusGraph.Net.IntegrationTest/DocTraversalsTests.cs +++ b/test/JanusGraph.Net.IntegrationTest/DocTraversalsTests.cs @@ -28,17 +28,17 @@ namespace JanusGraph.Net.IntegrationTest [Collection("JanusGraph Server collection")] public class DocTraversalsTests : IDisposable { - private readonly RemoteConnectionFactory _connectionFactory; + protected virtual RemoteConnectionFactory ConnectionFactory { get; } public DocTraversalsTests(JanusGraphServerFixture fixture) { - _connectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); } [Fact] public void GremlinNetGettingStartedTest() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var herculesAge = g.V().Has("name", "hercules").Values("age").Next(); @@ -48,7 +48,7 @@ public void GremlinNetGettingStartedTest() [Fact] public void ReceivingEdgesTest() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var edges = g.V().Has("name", "hercules").OutE("battled").ToList(); @@ -56,9 +56,9 @@ public void ReceivingEdgesTest() } [Fact] - public void TextContainsPredicateTest() + public virtual void TextContainsPredicateTest() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var reasons = g.E().Has("reason", Text.TextContains("loves")).ToList(); @@ -66,9 +66,9 @@ public void TextContainsPredicateTest() } [Fact] - public void GeoTypesPointsReceivedTest() + public virtual void GeoTypesPointsReceivedTest() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var firstBattlePlace = g.V().Has("name", "hercules").OutE("battled").Order().By("time") .Values("place").Next(); @@ -78,16 +78,16 @@ public void GeoTypesPointsReceivedTest() } [Fact] - public void GeoTypesPointAsArgumentTest() + public virtual void GeoTypesPointAsArgumentTest() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); g.V().Has("name", "hercules").OutE("battled").Has("place", Geoshape.Point(38.1f, 23.7f)).Next(); } public void Dispose() { - _connectionFactory?.Dispose(); + ConnectionFactory?.Dispose(); } } } \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/GraphBinaryDocTraversalsTests.cs b/test/JanusGraph.Net.IntegrationTest/GraphBinaryDocTraversalsTests.cs new file mode 100644 index 0000000..55f7361 --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/GraphBinaryDocTraversalsTests.cs @@ -0,0 +1,51 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; +using Gremlin.Net.Structure.IO.GraphBinary; +using JanusGraph.Net.IO.GraphBinary; +using Xunit; + +namespace JanusGraph.Net.IntegrationTest +{ + [Collection("JanusGraph Server collection")] + public class GraphBinaryDocTraversalsTests : DocTraversalsTests + { + protected override RemoteConnectionFactory ConnectionFactory { get; } + + public GraphBinaryDocTraversalsTests(JanusGraphServerFixture fixture) : base(fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port, + new GraphBinaryMessageSerializer(JanusGraphTypeSerializerRegistry.Instance)); + } + + [Fact(Skip = "Geoshapes not supported yet for GraphBinary")] + public override void GeoTypesPointsReceivedTest() + { + throw new NotImplementedException("GraphBinary support for Geo types not implemented yet."); + } + + [Fact(Skip = "Geoshapes not supported yet for GraphBinary")] + public override void GeoTypesPointAsArgumentTest() + { + throw new NotImplementedException("GraphBinary support for Geo types not implemented yet."); + } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/GraphBinaryTextTests.cs b/test/JanusGraph.Net.IntegrationTest/GraphBinaryTextTests.cs new file mode 100644 index 0000000..49dfa52 --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/GraphBinaryTextTests.cs @@ -0,0 +1,38 @@ +#region License + +/* + * Copyright 2018 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Gremlin.Net.Structure.IO.GraphBinary; +using JanusGraph.Net.IO.GraphBinary; +using Xunit; + +namespace JanusGraph.Net.IntegrationTest +{ + [Collection("JanusGraph Server collection")] + public class GraphBinaryTextTests : TextTests + { + public GraphBinaryTextTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port, + new GraphBinaryMessageSerializer(JanusGraphTypeSerializerRegistry.Instance)); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/GraphSONTextTests.cs b/test/JanusGraph.Net.IntegrationTest/GraphSONTextTests.cs new file mode 100644 index 0000000..2a0c01d --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/GraphSONTextTests.cs @@ -0,0 +1,36 @@ +#region License + +/* + * Copyright 2018 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Xunit; + +namespace JanusGraph.Net.IntegrationTest +{ + [Collection("JanusGraph Server collection")] + public class GraphSONTextTests : TextTests + { + public GraphSONTextTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = + new RemoteConnectionFactory(fixture.Host, fixture.Port); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GeoshapeDeserializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GeoshapeDeserializerTests.cs similarity index 71% rename from test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GeoshapeDeserializerTests.cs rename to test/JanusGraph.Net.IntegrationTest/IO/GeoshapeDeserializerTests.cs index 53e7fd5..d425dab 100644 --- a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GeoshapeDeserializerTests.cs +++ b/test/JanusGraph.Net.IntegrationTest/IO/GeoshapeDeserializerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2018 JanusGraph.Net Authors + * Copyright 2021 JanusGraph.Net Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,22 +24,17 @@ using Xunit; using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; -namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +namespace JanusGraph.Net.IntegrationTest.IO { [Collection("JanusGraph Server collection")] - public class GeoshapeDeserializerTests : IDisposable + public abstract class GeoshapeDeserializerTests : IDisposable { - private readonly RemoteConnectionFactory _connectionFactory; - - public GeoshapeDeserializerTests(JanusGraphServerFixture fixture) - { - _connectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); - } + protected abstract RemoteConnectionFactory ConnectionFactory { get; } [Fact] public async Task TraversalWithPointPropertyValue_PointReturned_ExpectedPoint() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var place = await g.V().Has("demigod", "name", "hercules").OutE("battled").Has("time", 1) .Values("place").Promise(t => t.Next()); @@ -51,7 +46,7 @@ public async Task TraversalWithPointPropertyValue_PointReturned_ExpectedPoint() public void Dispose() { - _connectionFactory?.Dispose(); + ConnectionFactory?.Dispose(); } } } \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GeoshapeSerializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GeoshapeSerializerTests.cs similarity index 69% rename from test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GeoshapeSerializerTests.cs rename to test/JanusGraph.Net.IntegrationTest/IO/GeoshapeSerializerTests.cs index 2e35f30..f658a97 100644 --- a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GeoshapeSerializerTests.cs +++ b/test/JanusGraph.Net.IntegrationTest/IO/GeoshapeSerializerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2018 JanusGraph.Net Authors + * Copyright 2021 JanusGraph.Net Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,22 +24,17 @@ using Xunit; using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; -namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +namespace JanusGraph.Net.IntegrationTest.IO { [Collection("JanusGraph Server collection")] - public class GeoshapeSerializerTests : IDisposable + public abstract class GeoshapeSerializerTests : IDisposable { - private readonly RemoteConnectionFactory _connectionFactory; - - public GeoshapeSerializerTests(JanusGraphServerFixture fixture) - { - _connectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); - } + protected abstract RemoteConnectionFactory ConnectionFactory { get; } [Fact] public async Task TraversalWithPointHasFilter_ExistingPoint_ElementFound() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.V().Has("demigod", "name", "hercules").OutE("battled") .Has("place", Geoshape.Point(38.1f, 23.7f)).Count().Promise(t => t.Next()); @@ -49,7 +44,7 @@ public async Task TraversalWithPointHasFilter_ExistingPoint_ElementFound() public void Dispose() { - _connectionFactory?.Dispose(); + ConnectionFactory?.Dispose(); } } } \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierDeserializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierDeserializerTests.cs new file mode 100644 index 0000000..c5c9a06 --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierDeserializerTests.cs @@ -0,0 +1,38 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Gremlin.Net.Structure.IO.GraphBinary; +using JanusGraph.Net.IO.GraphBinary; +using Xunit; + +namespace JanusGraph.Net.IntegrationTest.IO.GraphBinary +{ + [Collection("JanusGraph Server collection")] + public class GraphBinaryRelationIdentifierDeserializerTests : RelationIdentifierDeserializerTests + { + public GraphBinaryRelationIdentifierDeserializerTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port, + new GraphBinaryMessageSerializer(JanusGraphTypeSerializerRegistry.Instance)); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierSerializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierSerializerTests.cs new file mode 100644 index 0000000..710e2da --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/IO/GraphBinary/GraphBinaryRelationIdentifierSerializerTests.cs @@ -0,0 +1,38 @@ +#region License + +/* + * Copyright 2021 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Gremlin.Net.Structure.IO.GraphBinary; +using JanusGraph.Net.IO.GraphBinary; +using Xunit; + +namespace JanusGraph.Net.IntegrationTest.IO.GraphBinary +{ + [Collection("JanusGraph Server collection")] + public class GraphBinaryRelationIdentifierSerializerTests : RelationIdentifierSerializerTests + { + public GraphBinaryRelationIdentifierSerializerTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port, + new GraphBinaryMessageSerializer(JanusGraphTypeSerializerRegistry.Instance)); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeDeserializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeDeserializerTests.cs new file mode 100644 index 0000000..6084f10 --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeDeserializerTests.cs @@ -0,0 +1,35 @@ +#region License + +/* + * Copyright 2018 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Xunit; + +namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +{ + [Collection("JanusGraph Server collection")] + public class GraphSONGeoshapeDeserializerTests : GeoshapeDeserializerTests + { + public GraphSONGeoshapeDeserializerTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeSerializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeSerializerTests.cs new file mode 100644 index 0000000..07c9daa --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONGeoshapeSerializerTests.cs @@ -0,0 +1,35 @@ +#region License + +/* + * Copyright 2018 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Xunit; + +namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +{ + [Collection("JanusGraph Server collection")] + public class GraphSONGeoshapeSerializerTests : GeoshapeSerializerTests + { + public GraphSONGeoshapeSerializerTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierDeserializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierDeserializerTests.cs new file mode 100644 index 0000000..2829665 --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierDeserializerTests.cs @@ -0,0 +1,35 @@ +#region License + +/* + * Copyright 2018 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Xunit; + +namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +{ + [Collection("JanusGraph Server collection")] + public class GraphSONRelationIdentifierDeserializerTests : RelationIdentifierDeserializerTests + { + public GraphSONRelationIdentifierDeserializerTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierSerializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierSerializerTests.cs new file mode 100644 index 0000000..0bd1f20 --- /dev/null +++ b/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/GraphSONRelationIdentifierSerializerTests.cs @@ -0,0 +1,35 @@ +#region License + +/* + * Copyright 2018 JanusGraph.Net Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using Xunit; + +namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +{ + [Collection("JanusGraph Server collection")] + public class GraphSONRelationIdentifierSerializerTests : RelationIdentifierSerializerTests + { + public GraphSONRelationIdentifierSerializerTests(JanusGraphServerFixture fixture) + { + ConnectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); + } + + protected override RemoteConnectionFactory ConnectionFactory { get; } + } +} \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/RelationIdentifierDeserializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/RelationIdentifierDeserializerTests.cs similarity index 69% rename from test/JanusGraph.Net.IntegrationTest/IO/GraphSON/RelationIdentifierDeserializerTests.cs rename to test/JanusGraph.Net.IntegrationTest/IO/RelationIdentifierDeserializerTests.cs index e9ec94f..7202ad8 100644 --- a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/RelationIdentifierDeserializerTests.cs +++ b/test/JanusGraph.Net.IntegrationTest/IO/RelationIdentifierDeserializerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2018 JanusGraph.Net Authors + * Copyright 2021 JanusGraph.Net Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,22 +23,17 @@ using Xunit; using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; -namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +namespace JanusGraph.Net.IntegrationTest.IO { [Collection("JanusGraph Server collection")] - public class RelationIdentifierDeserializerTests : IDisposable + public abstract class RelationIdentifierDeserializerTests : IDisposable { - private readonly RemoteConnectionFactory _connectionFactory; - - public RelationIdentifierDeserializerTests(JanusGraphServerFixture fixture) - { - _connectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); - } + protected abstract RemoteConnectionFactory ConnectionFactory { get; } [Fact] public async Task TraversalWithEdgeId_RelationIdentifierReturned_ValidRelationIdentifier() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var relationIdentifier = await g.V().Has("demigod", "name", "hercules").OutE("father").Id().Promise(t => t.Next()); @@ -49,7 +44,7 @@ public async Task TraversalWithEdgeId_RelationIdentifierReturned_ValidRelationId [Fact] public async Task TraversalWithEdge_EdgeReturned_EdgeWithIdOfTypeRelationIdentifier() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var edge = await g.V().Has("demigod", "name", "hercules").OutE("father").Promise(t => t.Next()); @@ -58,7 +53,7 @@ public async Task TraversalWithEdge_EdgeReturned_EdgeWithIdOfTypeRelationIdentif public void Dispose() { - _connectionFactory?.Dispose(); + ConnectionFactory?.Dispose(); } } } \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/RelationIdentifierSerializerTests.cs b/test/JanusGraph.Net.IntegrationTest/IO/RelationIdentifierSerializerTests.cs similarity index 68% rename from test/JanusGraph.Net.IntegrationTest/IO/GraphSON/RelationIdentifierSerializerTests.cs rename to test/JanusGraph.Net.IntegrationTest/IO/RelationIdentifierSerializerTests.cs index cbcee51..2297ca7 100644 --- a/test/JanusGraph.Net.IntegrationTest/IO/GraphSON/RelationIdentifierSerializerTests.cs +++ b/test/JanusGraph.Net.IntegrationTest/IO/RelationIdentifierSerializerTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2018 JanusGraph.Net Authors + * Copyright 2021 JanusGraph.Net Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,22 +23,17 @@ using Xunit; using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; -namespace JanusGraph.Net.IntegrationTest.IO.GraphSON +namespace JanusGraph.Net.IntegrationTest.IO { [Collection("JanusGraph Server collection")] - public class RelationIdentifierSerializerTests : IDisposable + public abstract class RelationIdentifierSerializerTests : IDisposable { - private readonly RemoteConnectionFactory _connectionFactory; - - public RelationIdentifierSerializerTests(JanusGraphServerFixture fixture) - { - _connectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); - } + protected abstract RemoteConnectionFactory ConnectionFactory { get; } [Fact] public async Task TraversalWithRelationIdentifierAsEdgeId_ExistingEdgeId_EdgeFound() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var edgeId = await g.E().Id().Promise(t => t.Next()); var count = await g.E(edgeId).Count().Promise(t => t.Next()); @@ -49,7 +44,7 @@ public async Task TraversalWithRelationIdentifierAsEdgeId_ExistingEdgeId_EdgeFou [Fact] public async Task TraversalWithEdge_ExistingEdge_EdgeFound() { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var edge = await g.E().Promise(t => t.Next()); var count = await g.E(edge).Count().Promise(t => t.Next()); @@ -59,7 +54,7 @@ public async Task TraversalWithEdge_ExistingEdge_EdgeFound() public void Dispose() { - _connectionFactory?.Dispose(); + ConnectionFactory?.Dispose(); } } } \ No newline at end of file diff --git a/test/JanusGraph.Net.IntegrationTest/RemoteConnectionFactory.cs b/test/JanusGraph.Net.IntegrationTest/RemoteConnectionFactory.cs index fb430c9..3c40c47 100644 --- a/test/JanusGraph.Net.IntegrationTest/RemoteConnectionFactory.cs +++ b/test/JanusGraph.Net.IntegrationTest/RemoteConnectionFactory.cs @@ -23,25 +23,33 @@ using Gremlin.Net.Driver; using Gremlin.Net.Driver.Remote; using Gremlin.Net.Process.Remote; +using JanusGraph.Net.IO.GraphSON; namespace JanusGraph.Net.IntegrationTest { - internal class RemoteConnectionFactory : IDisposable + public class RemoteConnectionFactory : IDisposable { private readonly IList _connections = new List(); private readonly string _host; private readonly int _port; + private readonly IMessageSerializer _serializer; public RemoteConnectionFactory(string host, int port) + : this(host, port, new JanusGraphGraphSONMessageSerializer()) + { + } + + public RemoteConnectionFactory(string host, int port, IMessageSerializer serializer) { _host = host; _port = port; + _serializer = serializer; } public IRemoteConnection CreateRemoteConnection() { var c = new DriverRemoteConnection(JanusGraphClientBuilder - .BuildClientForServer(new GremlinServer(_host, _port)).Create()); + .BuildClientForServer(new GremlinServer(_host, _port)).WithSerializer(_serializer).Create()); _connections.Add(c); return c; } diff --git a/test/JanusGraph.Net.IntegrationTest/TextTests.cs b/test/JanusGraph.Net.IntegrationTest/TextTests.cs index 17b7ef9..975dcc0 100644 --- a/test/JanusGraph.Net.IntegrationTest/TextTests.cs +++ b/test/JanusGraph.Net.IntegrationTest/TextTests.cs @@ -20,28 +20,22 @@ using System; using System.Threading.Tasks; -using Gremlin.Net.Structure; using Xunit; using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; namespace JanusGraph.Net.IntegrationTest { [Collection("JanusGraph Server collection")] - public class TextTests : IDisposable + public abstract class TextTests : IDisposable { - private readonly RemoteConnectionFactory _connectionFactory; - - public TextTests(JanusGraphServerFixture fixture) - { - _connectionFactory = new RemoteConnectionFactory(fixture.Host, fixture.Port); - } + protected abstract RemoteConnectionFactory ConnectionFactory { get; } [Theory] [InlineData("loves", 2)] [InlineData("shouldNotBeFound", 0)] public async Task TextContainsgivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount) { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.E().Has("reason", Text.TextContains(searchText)).Count().Promise(t => t.Next()); @@ -54,7 +48,7 @@ public async Task TextContainsgivenSearchText_ExpectedCountOfElements(string sea [InlineData("shouldNotBeFound", 0)] public async Task TextContainsPrefixgivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount) { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.E().Has("reason", Text.TextContainsPrefix(searchText)).Count().Promise(t => t.Next()); @@ -67,7 +61,7 @@ public async Task TextContainsPrefixgivenSearchText_ExpectedCountOfElements(stri [InlineData("shouldNotBeFound", 0)] public async Task TextContainsRegexgivenRegex_ExpectedCountOfElements(string regex, int expectedCount) { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.E().Has("reason", Text.TextContainsRegex(regex)).Count().Promise(t => t.Next()); @@ -79,7 +73,7 @@ public async Task TextContainsRegexgivenRegex_ExpectedCountOfElements(string reg [InlineData("shouldNotBeFound", 0)] public async Task TextContainsFuzzygivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount) { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.E().Has("reason", Text.TextContainsFuzzy(searchText)).Count().Promise(t => t.Next()); @@ -92,7 +86,7 @@ public async Task TextContainsFuzzygivenSearchText_ExpectedCountOfElements(strin [InlineData("shouldNotBeFound", 0)] public async Task TextPrefixgivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount) { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.V().Has("name", Text.TextPrefix(searchText)).Count().Promise(t => t.Next()); @@ -105,7 +99,7 @@ public async Task TextPrefixgivenSearchText_ExpectedCountOfElements(string searc [InlineData("shouldNotBeFound", 0)] public async Task TextRegexgivenRegex_ExpectedCountOfElements(string regex, int expectedCount) { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.V().Has("name", Text.TextRegex(regex)).Count().Promise(t => t.Next()); @@ -118,7 +112,7 @@ public async Task TextRegexgivenRegex_ExpectedCountOfElements(string regex, int [InlineData("shouldNotBeFound", 0)] public async Task TextFuzzygivenSearchText_ExpectedCountOfElements(string searchText, int expectedCount) { - var g = Traversal().WithRemote(_connectionFactory.CreateRemoteConnection()); + var g = Traversal().WithRemote(ConnectionFactory.CreateRemoteConnection()); var count = await g.V().Has("name", Text.TextFuzzy(searchText)).Count().Promise(t => t.Next()); @@ -127,7 +121,7 @@ public async Task TextFuzzygivenSearchText_ExpectedCountOfElements(string search public void Dispose() { - _connectionFactory?.Dispose(); + ConnectionFactory?.Dispose(); } } } \ No newline at end of file diff --git a/test/JanusGraph.Net.UnitTest/IO/GraphSON/RelationIdentifierSerializationSymmetricyTests.cs b/test/JanusGraph.Net.UnitTest/IO/GraphSON/RelationIdentifierSerializationSymmetricyTests.cs index 49c6a52..9b1f758 100644 --- a/test/JanusGraph.Net.UnitTest/IO/GraphSON/RelationIdentifierSerializationSymmetricyTests.cs +++ b/test/JanusGraph.Net.UnitTest/IO/GraphSON/RelationIdentifierSerializationSymmetricyTests.cs @@ -29,7 +29,7 @@ public class RelationIdentifierSerializationSymmetricyTests [Fact] public void SerializeAndDeserialize_ValidRelationIdentifier_SameRelationIdentifier() { - var relationIdentifier = new RelationIdentifier("someRelationId"); + var relationIdentifier = new RelationIdentifier("4qp-360-7x1-3aw"); var writer = JanusGraphSONWriterBuilder.Build().Create(); var reader = JanusGraphSONReaderBuilder.Build().Create(); diff --git a/test/JanusGraph.Net.UnitTest/RelationIdentifierTests.cs b/test/JanusGraph.Net.UnitTest/RelationIdentifierTests.cs index 73ad1b6..910616b 100644 --- a/test/JanusGraph.Net.UnitTest/RelationIdentifierTests.cs +++ b/test/JanusGraph.Net.UnitTest/RelationIdentifierTests.cs @@ -32,5 +32,25 @@ public void ToString_ValidRelationId_RelationId() Assert.Equal(relationId, relationIdentifier.ToString()); } + + [Fact] + public void CtrWithStr_ValidRelationId_ExpectedLongValues() + { + var relationIdentifier = new RelationIdentifier("4qp-360-7x1-3aw"); + + Assert.Equal(4104, relationIdentifier.OutVertexId); + Assert.Equal(10261, relationIdentifier.TypeId); + Assert.Equal(6145, relationIdentifier.RelationId); + Assert.Equal(4280, relationIdentifier.InVertexId); + } + + [Fact] + public void CtrWithLongs_ValidLongValues_ExpectedStringRepresentation() + { + var relationIdentifier = new RelationIdentifier(4104, 10261, 6145, 4280); + + Assert.Equal("4qp-360-7x1-3aw", relationIdentifier.StringRepresentation); + Assert.Equal("4qp-360-7x1-3aw", relationIdentifier.ToString()); + } } } \ No newline at end of file