| #region License |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.Collections.Generic; |
| using System.Collections.ObjectModel; |
| using System.Linq; |
| using Gherkin.Ast; |
| using Gremlin.Net.Driver; |
| using Gremlin.Net.Driver.Exceptions; |
| using Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection; |
| using Gremlin.Net.Process.Remote; |
| using Gremlin.Net.Process.Traversal; |
| using Gremlin.Net.Structure; |
| |
| using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource; |
| |
| namespace Gremlin.Net.IntegrationTest.Gherkin |
| { |
| internal class ScenarioData : IDisposable |
| { |
| private static readonly string[] GraphNames = {"modern", "classic", "crew", "grateful", "sink"}; |
| |
| private static readonly IDictionary<string, Vertex> EmptyVertices = |
| new ReadOnlyDictionary<string, Vertex>(new Dictionary<string, Vertex>()); |
| |
| private static readonly IDictionary<string, Edge> EmptyEdges = |
| new ReadOnlyDictionary<string, Edge>(new Dictionary<string, Edge>()); |
| |
| private static readonly IDictionary<string, VertexProperty> EmptyVertexProperties = |
| new ReadOnlyDictionary<string, VertexProperty>(new Dictionary<string, VertexProperty>()); |
| |
| private readonly RemoteConnectionFactory _connectionFactory; |
| |
| public Scenario? CurrentScenario; |
| public Feature? CurrentFeature; |
| |
| public ScenarioDataPerGraph GetByGraphName(string name) |
| { |
| if (name == null) |
| { |
| throw new ArgumentNullException(nameof(name), "Graph name can not be empty"); |
| } |
| if (!_dataPerGraph.TryGetValue(name, out var data)) |
| { |
| throw new KeyNotFoundException($"Graph data with key '{name}' not found"); |
| } |
| return data; |
| } |
| |
| public void CleanEmptyData() |
| { |
| var g = Traversal().WithRemote(GetByGraphName("empty").Connection); |
| g.V().Drop().Iterate(); |
| } |
| |
| public void ReloadEmptyData() |
| { |
| var graphData = _dataPerGraph["empty"]; |
| var g = Traversal().WithRemote(graphData.Connection); |
| graphData.Vertices = GetVertices(g); |
| graphData.Edges = GetEdges(g); |
| graphData.VertexProperties = GetVertexProperties(g); |
| } |
| |
| private readonly IDictionary<string, ScenarioDataPerGraph> _dataPerGraph; |
| |
| public ScenarioData(IMessageSerializer messageSerializer) |
| { |
| _connectionFactory = new RemoteConnectionFactory(messageSerializer); |
| _dataPerGraph = LoadDataPerGraph(); |
| var empty = new ScenarioDataPerGraph("empty", _connectionFactory.CreateRemoteConnection("ggraph"), |
| new Dictionary<string, Vertex>(0), new Dictionary<string, Edge>(), new Dictionary<string, VertexProperty>()); |
| _dataPerGraph.Add("empty", empty); |
| } |
| |
| private Dictionary<string, ScenarioDataPerGraph> LoadDataPerGraph() |
| { |
| return GraphNames.Select(name => |
| { |
| var connection = _connectionFactory.CreateRemoteConnection($"g{name}"); |
| var g = Traversal().WithRemote(connection); |
| return new ScenarioDataPerGraph(name, connection, GetVertices(g), GetEdges(g), GetVertexProperties(g)); |
| }).ToDictionary(x => x.Name); |
| } |
| |
| private static IDictionary<string, Vertex> GetVertices(GraphTraversalSource g) |
| { |
| // Property name might not exist and C# doesn't support "null" keys in Dictionary |
| if (g.V().Count().Next() == g.V().Has("name").Count().Next()) |
| { |
| return g.V().Group<string, object>().By("name").By(__.Tail<Vertex>()).Next()! |
| .ToDictionary(kv => kv.Key, kv => (Vertex) kv.Value); |
| } |
| else |
| { |
| return EmptyVertices; |
| } |
| } |
| |
| private static IDictionary<string, Edge> GetEdges(GraphTraversalSource g) |
| { |
| try |
| { |
| IFunction lambda = Lambda.Groovy( |
| "it.outVertex().value('name') + '-' + it.label() + '->' + it.inVertex().value('name')", 1); |
| |
| return g.E().Group<string, Edge>() |
| .By(lambda) |
| .By(__.Tail<object>()) |
| .Next()!; |
| } |
| catch (ResponseException) |
| { |
| // Property name might not exist |
| return EmptyEdges; |
| } |
| } |
| |
| private static IDictionary<string, VertexProperty> GetVertexProperties(GraphTraversalSource g) |
| { |
| try |
| { |
| /* |
| * This closure will turn a VertexProperty into a triple string of the form: |
| * "vertexName-propKey->propVal" |
| * |
| * It will also take care of wrapping propVal in the appropriate Numeric format. We must do this in |
| * case a Vertex has multiple properties with the same key and number value but in different numeric |
| * type spaces (rare, but possible, and presumably something we may want to write tests around). |
| */ |
| var groovy = @" |
| { vp -> |
| def result = vp.element().value('name') + '-' + vp.key() + '->' |
| def value = vp.value() |
| def type = '' |
| switch(value) { |
| case { !(it instanceof Number) }: |
| return result + value |
| case Byte: |
| type = 'b' |
| break |
| case Short: |
| type = 's' |
| break |
| case Integer: |
| type = 'i' |
| break |
| case Long: |
| type = 'l' |
| break |
| case Float: |
| type = 'f' |
| break |
| case Double: |
| type = 'd' |
| break |
| case BigDecimal: |
| type = 'm' |
| break |
| case BigInteger: |
| type = 'n' |
| break |
| } |
| return result + 'd[' + value + '].' + type |
| } |
| "; |
| |
| IFunction lambda = Lambda.Groovy(groovy, 1); |
| |
| return g.V().Properties<VertexProperty>().Group<string, VertexProperty>() |
| .By(lambda) |
| .By(__.Tail<object>()) |
| .Next()!; |
| } |
| catch (ResponseException) |
| { |
| return EmptyVertexProperties; |
| } |
| } |
| |
| public void Dispose() |
| { |
| _connectionFactory?.Dispose(); |
| } |
| } |
| |
| internal class ScenarioDataPerGraph |
| { |
| public ScenarioDataPerGraph(string name, IRemoteConnection connection, IDictionary<string, Vertex> vertices, |
| IDictionary<string, Edge> edges, IDictionary<string, VertexProperty> vertexProperties) |
| { |
| Name = name; |
| Connection = connection; |
| Vertices = vertices; |
| Edges = edges; |
| VertexProperties = vertexProperties; |
| } |
| |
| public string Name { get; } |
| |
| public IRemoteConnection Connection { get; } |
| |
| public IDictionary<string, Vertex> Vertices { get; set; } |
| |
| public IDictionary<string, Edge> Edges { get; set; } |
| |
| public IDictionary<string, VertexProperty> VertexProperties { get; set; } |
| } |
| } |