Created
March 31, 2012 11:15
-
-
Save PaulStovell/2262298 to your computer and use it in GitHub Desktop.
Hierarchies in RavenDB
This file contains hidden or 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
public class Group | |
{ | |
public Group() | |
{ | |
Users = new List<string>(); | |
ChildGroups = new List<string>(); | |
} | |
public string Id { get; set; } | |
public string Name { get; set; } | |
public IList<string> Users { get; set; } | |
public IList<string> ChildGroups { get; set; } | |
} |
This file contains hidden or 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
// This index inverts the relationship between groups and child groups into groups and their direct parents | |
// E.g., from this: | |
// { All users, [ Technical, Management ] } | |
// { Technical, [ Developers, Release Managers ] } | |
// { Super Users, [ Release Managers ] } | |
// We get this: | |
// { Technical, [ All users ] } | |
// { Management, [ All users ] } | |
// { Developers, [ Technical ] } | |
// { Release Managers, [ Technical, Super Users ] } | |
public class GroupDirectParents : AbstractIndexCreationTask<Group, GroupDirectParents.Result> | |
{ | |
public GroupDirectParents() | |
{ | |
Map = groups => from g in groups | |
from child in g.ChildGroups | |
select new Result { GroupId = child, ParentGroupIds = new[] { g.Id } }; | |
Reduce = results => from r in results | |
group r by r.GroupId into g | |
select new Result { GroupId = g.Key, ParentGroupIds = g.SelectMany(i => i.ParentGroupIds).ToArray() }; | |
} | |
public class Result | |
{ | |
public string GroupId { get; set; } | |
public string[] ParentGroupIds { get; set; } | |
} | |
} |
This file contains hidden or 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
// This index is similar to above. However, it will work recursively such that it returns all parent groups of a group | |
// E.g., from this: | |
// { All users, [ Technical, Management ] } | |
// { Technical, [ Developers, Release Managers ] } | |
// { Super users, [ Release Managers ] } | |
// We get this: | |
// { Technical, [ All users ] } | |
// { Management, [ All users ] } | |
// { Developers, [ Technical, All users ] } | |
// { Release Managers, [ Technical, Super users, All users ] } | |
public class GroupIndirectParents : AbstractIndexCreationTask<Group, GroupIndirectParents.Result> | |
{ | |
public GroupIndirectParents() | |
{ | |
Map = ?? | |
Reduce = ?? | |
} | |
public class Result | |
{ | |
public string GroupId { get; set; } | |
public string[] ParentGroupIds { get; set; } | |
} | |
} |
This file contains hidden or 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
[TestFixture] | |
public class Tests | |
{ | |
private DocumentStore documentStore; | |
[SetUp] | |
public void SetUp() | |
{ | |
documentStore = new EmbeddableDocumentStore { RunInMemory = true }; | |
documentStore.Initialize(); | |
IndexCreation.CreateIndexes(typeof(GroupDirectParents).Assembly, documentStore); | |
// Build a tree of groups - | |
// G: Everyone | |
// G: Characters | |
// G: Male | |
// G: Females | |
using (var session = documentStore.OpenSession()) | |
{ | |
session.Store(new Group(), "groups/everyone"); | |
session.Store(new Group(), "groups/characters"); | |
session.Store(new Group(), "groups/males"); | |
session.Store(new Group(), "groups/females"); | |
session.SaveChanges(); | |
session.Load<Group>("groups/everyone").ChildGroups.Add("groups/characters"); | |
session.Load<Group>("groups/characters").ChildGroups.Add("groups/males"); | |
session.Load<Group>("groups/characters").ChildGroups.Add("groups/females"); | |
session.SaveChanges(); | |
} | |
} | |
// This test passes | |
[Test] | |
public void ShouldFindDirectParentsForGroups() | |
{ | |
using (var session = documentStore.OpenSession()) | |
{ | |
// This index gives us the first parent group of each group | |
var results = session.Query<GroupDirectParents.Result, GroupDirectParents>().Customize(c => c.WaitForNonStaleResultsAsOfNow(TimeSpan.FromSeconds(30))).ToList(); | |
AssertGroupHasParents(results, "groups/males", "groups/characters"); | |
AssertGroupHasParents(results, "groups/females", "groups/characters"); | |
} | |
} | |
// This test doesn't pass, but I want it to | |
[Test] | |
public void ShouldFindIndirectParentsForGroups() | |
{ | |
using (var session = documentStore.OpenSession()) | |
{ | |
// This index gives us the *all* parent groups of each group, both direct parents and all ancestors | |
var results = session.Query<GroupIndirectParents.Result, GroupIndirectParents>().Customize(c => c.WaitForNonStaleResultsAsOfNow(TimeSpan.FromSeconds(30))).ToList(); | |
// Note that in this case, we're testing on the parent of a parent | |
AssertGroupHasParents(results, "groups/males", "groups/characters", "groups/everyone"); | |
AssertGroupHasParents(results, "groups/females", "groups/characters", "groups/everyone"); | |
AssertGroupHasParents(results, "groups/characters", "groups/everyone"); | |
} | |
} | |
private void AssertGroupHasParents(IEnumerable<GroupDirectParents.Result> results, string group, params string[] parents) | |
{ | |
var groupParents = results.FirstOrDefault(r => r.GroupId == group); | |
Assert.IsNotNull(groupParents, "Could not find an index record for group: " + group); | |
CollectionAssert.AreEquivalent(parents, groupParents.ParentGroupIds); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment