Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added GraphModel Generally lifted from OrigoDB: https://raw.githubusercontent.com/DevrexLabs/OrigoDB/dev/src/OrigoDB.Core/Modeling/GraphModel.cs Added tests including end-to-end smoke tests covering basic usage and proving journaling/replaying of graph. * PR-67 Resolves issues in graph model
- Loading branch information
Showing
12 changed files
with
513 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace Memstate.Models.Graph | ||
{ | ||
public partial class GraphModel | ||
{ | ||
public class Edge : Item | ||
{ | ||
public Edge(long id, string label) : base(id, label) { } | ||
|
||
public Node From; | ||
public Node To; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq.Expressions; | ||
|
||
namespace Memstate.Models.Graph | ||
{ | ||
public partial class GraphModel | ||
{ | ||
/// <summary> | ||
/// Unique id generator, shared by nodes and edges | ||
/// </summary> | ||
private long _lastId; | ||
|
||
//Nodes and edges | ||
private readonly SortedDictionary<long, Node> _nodesById; | ||
private readonly SortedDictionary<long, Edge> _edgesById; | ||
|
||
private SortedDictionary<string, SortedSet<Node>> _nodesByLabel; | ||
private SortedDictionary<string, SortedSet<Edge>> _edgesByLabel; | ||
|
||
|
||
public IEnumerable<Node> Nodes | ||
{ | ||
get { return _nodesById.Values; } | ||
} | ||
|
||
public IEnumerable<Edge> Edges | ||
{ | ||
get { return _edgesById.Values; } | ||
} | ||
|
||
public GraphModel() | ||
{ | ||
var ignoreCase = StringComparer.OrdinalIgnoreCase; | ||
_edgesById = new SortedDictionary<long, Edge>(); | ||
_edgesByLabel = new SortedDictionary<string, SortedSet<Edge>>(ignoreCase); | ||
_nodesById = new SortedDictionary<long, Node>(); | ||
_nodesByLabel = new SortedDictionary<string, SortedSet<Node>>(ignoreCase); | ||
} | ||
|
||
public long CreateNode(string label) | ||
{ | ||
var id = ++_lastId; | ||
var node = new Node(id, label); | ||
_nodesById[id] = node; | ||
AddByLabel(_nodesByLabel, node, label); | ||
return id; | ||
} | ||
|
||
public long CreateEdge(long fromId, long toId, string label) | ||
{ | ||
Node from = NodeById(fromId); | ||
Node to = NodeById(toId); | ||
var id = ++_lastId; | ||
var edge = new Edge(id, label) { From = from, To = to }; | ||
_edgesById[id] = edge; | ||
AddByLabel(_edgesByLabel, edge, label); | ||
from.Out.Add(edge); | ||
to.In.Add(edge); | ||
return id; | ||
} | ||
|
||
public void RemoveEdge(long id) | ||
{ | ||
var edge = EdgeById(id); | ||
_edgesById.Remove(id); | ||
edge.From.Out.Remove(edge); | ||
edge.To.In.Remove(edge); | ||
_edgesByLabel[edge.Label].Remove(edge); | ||
} | ||
|
||
public void RemoveNode(long id) | ||
{ | ||
var node = NodeById(id); | ||
foreach (var edge in node.Out) RemoveEdge(edge.Id); | ||
foreach (var edge in node.In) RemoveEdge(edge.Id); | ||
_nodesById.Remove(id); | ||
_nodesByLabel[node.Label].Remove(node); | ||
} | ||
|
||
public T Query<T>(Expression<Func<GraphModel, T>> query) | ||
{ | ||
return query.Compile().Invoke(this); | ||
} | ||
|
||
private Node NodeById(long id) | ||
{ | ||
return GetById(_nodesById, id); | ||
} | ||
|
||
private Edge EdgeById(long id) | ||
{ | ||
return GetById(_edgesById, id); | ||
} | ||
|
||
private T GetById<T>(IDictionary<long, T> items, long id) | ||
{ | ||
if (items.TryGetValue(id, out var item)) return item; | ||
throw new ArgumentException("No such node: " + id); | ||
} | ||
|
||
private static void AddByLabel<T>(IDictionary<string, SortedSet<T>> index, T item, string label) | ||
{ | ||
SortedSet<T> set; | ||
if (!index.TryGetValue(label, out set)) | ||
{ | ||
set = new SortedSet<T>(); | ||
index[label] = set; | ||
} | ||
set.Add(item); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Memstate.Models.Graph | ||
{ | ||
public partial class GraphModel | ||
{ | ||
[Serializable] | ||
public abstract class Item : IComparable<Item> | ||
{ | ||
public readonly long Id; | ||
public readonly string Label; | ||
public readonly SortedDictionary<string, object> Props; | ||
|
||
protected Item(long id, string label) | ||
{ | ||
Id = id; | ||
Label = label; | ||
Props = new SortedDictionary<string, object>(StringComparer.OrdinalIgnoreCase); | ||
} | ||
|
||
public object Get(string key) | ||
{ | ||
object result; | ||
Props.TryGetValue(key, out result); | ||
return result; | ||
} | ||
|
||
public void Set(string key, object value) | ||
{ | ||
Props[key] = value; | ||
} | ||
|
||
public int CompareTo(Item other) | ||
{ | ||
return Math.Sign(Id - other.Id); | ||
} | ||
|
||
public override bool Equals(object obj) | ||
{ | ||
return obj != null | ||
&& obj.GetType() == GetType() //Edge == Node should always be false | ||
&& ((Item)obj).Id == Id; | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
return Id.GetHashCode(); | ||
} | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Memstate.Models.Graph | ||
{ | ||
public partial class GraphModel | ||
{ | ||
public class Node : Item | ||
{ | ||
public Node(long id, string label) : base(id, label) { } | ||
|
||
public ISet<Edge> Out = new SortedSet<Edge>(); | ||
public ISet<Edge> In = new SortedSet<Edge>(); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/Memstate.Docs.GettingStarted/QuickStartGraph/Commands/CreateEdge.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Memstate.Models.Graph; | ||
using System.Linq; | ||
using static Memstate.Models.Graph.GraphModel; | ||
|
||
namespace Memstate.Docs.GettingStarted.QuickStartGraph.Commands | ||
{ | ||
public class CreateEdge : Command<GraphModel, Edge> | ||
{ | ||
public long From { get; private set; } | ||
public long To { get; private set; } | ||
public string Label { get; private set; } | ||
|
||
public CreateEdge(long from, long to, string label) | ||
{ | ||
From = from; | ||
To = to; | ||
Label = label; | ||
} | ||
|
||
public override Edge Execute(GraphModel model) | ||
{ | ||
var edgeId = model.CreateEdge(From, To, Label); | ||
return model.Edges.Single(e => e.Id == edgeId); | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/Memstate.Docs.GettingStarted/QuickStartGraph/Commands/CreateNode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using Memstate.Models.Graph; | ||
using System.Linq; | ||
using static Memstate.Models.Graph.GraphModel; | ||
|
||
namespace Memstate.Docs.GettingStarted.QuickStartGraph.Commands | ||
{ | ||
public class CreateNode : Command<GraphModel, Node> | ||
{ | ||
public string Label { get; private set; } | ||
|
||
public CreateNode(string label) | ||
{ | ||
Label = label; | ||
} | ||
|
||
public override Node Execute(GraphModel model) | ||
{ | ||
var nodeId = model.CreateNode(Label); | ||
return model.Nodes.Single(n => n.Id == nodeId); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
src/Memstate.Docs.GettingStarted/QuickStartGraph/Commands/IncrementLikes.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using Memstate.Models.Graph; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using static Memstate.Models.Graph.GraphModel; | ||
|
||
namespace Memstate.Docs.GettingStarted.QuickStartGraph.Commands | ||
{ | ||
public class IncrementLikes : Command<GraphModel, Node> | ||
{ | ||
public long TweetId { get; private set; } | ||
|
||
public IncrementLikes(long id) | ||
{ | ||
TweetId = id; | ||
} | ||
|
||
public override Node Execute(GraphModel model) | ||
{ | ||
var tweet = model.Nodes.SingleOrDefault(n => n.Id == TweetId); | ||
object likes = tweet.Get("likes") ?? (long)0; | ||
tweet.Set("likes", (long)likes + 1); | ||
return tweet; | ||
} | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/Memstate.Docs.GettingStarted/QuickStartGraph/Queries/GetEdges.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using Memstate.Models.Graph; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using static Memstate.Models.Graph.GraphModel; | ||
|
||
namespace Memstate.Docs.GettingStarted.QuickStartGraph.Queries | ||
{ | ||
public class GetEdges : Query<GraphModel, IEnumerable<Edge>> | ||
{ | ||
public override IEnumerable<Edge> Execute(GraphModel db) => new List<Edge>(db.Edges); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/Memstate.Docs.GettingStarted/QuickStartGraph/Queries/GetNodes.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using Memstate.Models.Graph; | ||
using System.Collections.Generic; | ||
using static Memstate.Models.Graph.GraphModel; | ||
|
||
namespace Memstate.Docs.GettingStarted.QuickStartGraph.Queries | ||
{ | ||
public class GetNodes : Query<GraphModel, IEnumerable<Node>> | ||
{ | ||
public override IEnumerable<Node> Execute(GraphModel db) => new List<Node>(db.Nodes); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/Memstate.Docs.GettingStarted/QuickStartGraph/Queries/GetUsersWithTweets.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using Memstate.Models.Graph; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using static Memstate.Models.Graph.GraphModel; | ||
|
||
namespace Memstate.Docs.GettingStarted.QuickStartGraph.Queries | ||
{ | ||
public class GetUsersWithTweets : Query<GraphModel, IEnumerable<Node>> | ||
{ | ||
public override IEnumerable<Node> Execute(GraphModel db) | ||
{ | ||
var users = db.Nodes.Where(n => n.Label == "user"); | ||
var tweetEdges = users.SelectMany(e => e.Out.Where(r => r.Label == "tweeted")); | ||
var tweets = tweetEdges.Select(e => e.To); | ||
return tweets; | ||
} | ||
} | ||
} |
Oops, something went wrong.