Last active
December 14, 2015 07:38
-
-
Save pauldambra/5051550 to your computer and use it in GitHub Desktop.
Trying to understand why I suck at making RavenDB indexes
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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using Raven.Client; | |
using Raven.Client.Embedded; | |
using Raven.Client.Indexes; | |
using Raven.Client.Listeners; | |
using Xunit; | |
namespace BmcMailTests | |
{ | |
/// <summary> | |
/// Requires Xunit, RavenDB.Embedded and RavenDB.Client. | |
/// Which were installed using Nuget. Version 2.0.2261 of Raven and | |
/// 1.9.1 Xunit | |
/// Demonstrates an attempt to write a RavenDB index that fails magnificently | |
/// </summary> | |
public class RavenIndexTest | |
{ | |
[Fact] | |
public void DemonstrateAssertionsPassWhenIndexIsNotUsed() | |
{ | |
var documentStore = SetupDocumentStore(); | |
using (documentStore) | |
{ | |
SetupData(documentStore); | |
TestDataWithoutUsingIndex(documentStore); | |
} | |
} | |
[Fact] | |
public void DemonstrateAssertionsFailWhenIndexIsUsed() | |
{ | |
var documentStore = SetupDocumentStore(); | |
using (documentStore) | |
{ | |
SetupData(documentStore); | |
using (var session = documentStore.OpenSession()) | |
{ | |
var results = session.Query<MailingWithRecipientCount.Result, | |
MailingWithRecipientCount>(); | |
Assert.NotNull(results); | |
//calling ToList() throws Input string was not in a correct format. | |
List<MailingWithRecipientCount.Result> resultsList = null; | |
try | |
{ | |
resultsList = results.ToList(); | |
} | |
catch (FormatException e) | |
{ | |
Assert.True(false,e.Message); | |
} | |
Assert.NotNull(resultsList); | |
Assert.Equal(1, resultsList.Count()); | |
Assert.Equal(10, resultsList.First().RecipientCount); | |
} | |
} | |
} | |
private static void TestDataWithoutUsingIndex(IDocumentStore documentStore) | |
{ | |
using (var proofSession = documentStore.OpenSession()) | |
{ | |
//prove the mailing is there | |
var allMailings = proofSession.Query<Mailing>(); | |
Assert.NotNull(allMailings); | |
Assert.Equal(1, allMailings.Count()); | |
Assert.Equal(1, allMailings.First().Id); | |
//prove the recipients are there | |
var allRecipients = proofSession.Query<Recipient>(); | |
Assert.NotNull(allRecipients); | |
Assert.Equal(10, allRecipients.Count()); | |
Assert.Equal(4, allRecipients.Count(ar => ar.Status == RecipientStatus.Pending)); | |
Assert.Equal(6, allRecipients.Count(ar => ar.Status == RecipientStatus.Mailed)); | |
} | |
} | |
private static void SetupData(IDocumentStore documentStore) | |
{ | |
using (var setupSession = documentStore.OpenSession()) | |
{ | |
setupSession.Store(new Mailing | |
{ | |
Sender = "a sender", | |
Subject = "a subject" | |
}); | |
for (var i = 0; i < 4; i++) | |
{ | |
setupSession.Store(new Recipient {MailingId = 1}); | |
} | |
for (var i = 0; i < 6; i++) | |
{ | |
setupSession.Store(new Recipient | |
{ | |
MailingId = 1, | |
Status = RecipientStatus.Mailed | |
}); | |
} | |
setupSession.SaveChanges(); | |
} | |
} | |
private static EmbeddableDocumentStore SetupDocumentStore() | |
{ | |
var documentStore = new EmbeddableDocumentStore {RunInMemory = true}; | |
//setup the store | |
documentStore.RegisterListener(new NoStaleQueriesAllowed()); | |
documentStore.Initialize(); | |
IndexCreation.CreateIndexes(Assembly.GetExecutingAssembly(), documentStore); | |
return documentStore; | |
} | |
public class NoStaleQueriesAllowed : IDocumentQueryListener | |
{ | |
public void BeforeQueryExecuted(IDocumentQueryCustomization queryCustomization) | |
{ | |
queryCustomization.WaitForNonStaleResults(); | |
} | |
} | |
public class Mailing | |
{ | |
public Mailing() | |
{ | |
Created = DateTime.Now; | |
} | |
public int Id { get; set; } | |
public string Sender { get; set; } | |
public string Subject { get; set; } | |
public DateTime Created { get; set; } | |
} | |
public enum RecipientStatus | |
{ | |
Pending, | |
Sending, | |
Mailed, | |
Cancelled, | |
Bad | |
} | |
public class Recipient | |
{ | |
public Recipient() | |
{ | |
Status = RecipientStatus.Pending; | |
} | |
public RecipientStatus Status { get; set; } | |
public int MailingId { get; set; } | |
} | |
public class MailingWithRecipientCount : AbstractMultiMapIndexCreationTask<MailingWithRecipientCount.Result> | |
{ | |
public class Result | |
{ | |
public int MailingId { get; set; } | |
public string MailingSubject { get; set; } | |
public string MailingSender { get; set; } | |
public int RecipientCount { get; set; } | |
} | |
public MailingWithRecipientCount() | |
{ | |
AddMap<Mailing>(mailings => from mailing in mailings | |
select new | |
{ | |
MailingId = mailing.Id, | |
MailingSender = mailing.Sender, | |
MailingSubject = mailing.Subject, | |
RecipientCount = 0 | |
}); | |
AddMap<Recipient>(recipients => from recipient in recipients | |
select new | |
{ | |
recipient.MailingId, | |
MailingSender = (string)null, | |
MailingSubject = (string)null, | |
RecipientCount = 1 | |
}); | |
Reduce = results => from result in results | |
group result by result.MailingId | |
into g | |
select new | |
{ | |
MailingId = g.Key, | |
g.First(result => result != null).MailingSender, | |
g.First(result => result != null).MailingSubject, | |
RecipientCount = g.Sum(r => r.RecipientCount) | |
}; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment