Skip to content

Commit

Permalink
Merge pull request #2 from seankearon/master
Browse files Browse the repository at this point in the history
Collection migrations, thanks Sean Kearon!
  • Loading branch information
khalidabuhakmeh committed Oct 25, 2013
2 parents 4b20f50 + 9d05e7b commit 336d47c
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 0 deletions.
161 changes: 161 additions & 0 deletions RavenMigrations.Tests/CollectionMigrationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
using System.Linq;
using FluentAssertions;
using Raven.Abstractions.Data;
using Raven.Client;
using Raven.Client.Indexes;
using Raven.Json.Linq;
using Raven.Tests.Helpers;
using RavenMigrations.Tests.Old;
using Xunit;

namespace RavenMigrations.Tests
{
namespace Old
{
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
}
}

namespace New
{
public class Person
{
public string FirstName { get; set; }
public string Id { get; set; }
public string LastName { get; set; }
}
}

public class CollectionMigrationTests : RavenTestBase
{
[Fact]
public void Can_migrate_down()
{
using (var store = NewDocumentStore())
{
InitialiseWithPerson(store, "Sean Kearon");

var migration = new CollectionDocumentMigration();
migration.Setup(store);
migration.Up();
WaitForIndexing(store);

migration.Down();
UpdateCollectionMetadataToAllowLoadingByType<Person>(store, "People");
WaitForIndexing(store);

using (var session = store.OpenSession())
{
var customer = session.Load<Person>("People/1");
customer.Name.Should().Be("Sean Kearon");
}
}
}

[Fact]
public void Can_migrate_up()
{
using (var store = NewDocumentStore())
{
InitialiseWithPerson(store, "Sean Kearon");
var migration = new CollectionDocumentMigration();
migration.Setup(store);
migration.Up();
WaitForIndexing(store);

using (var session = store.OpenSession())
{
var customer = session.Load<New.Person>("People/1");
customer.FirstName.Should().Be("Sean");
customer.LastName.Should().Be("Kearon");
}
}
}

private void AddInitialPerson(IDocumentStore store, string name)
{
using (var session = store.OpenSession())
{
session.Store(new Person {Name = name});
session.SaveChanges();
}
}

private string GetMetadataClrTypeName<T>()
{
return string.Join(",", typeof (T).AssemblyQualifiedName.Split(new[] {','}).Take(2));
}

private void InitialiseWithPerson(IDocumentStore store, string name)
{
new RavenDocumentsByEntityName().Execute(store); //https://groups.google.com/forum/#!topic/ravendb/QqZPrRUwEkE
AddInitialPerson(store, name);
UpdateCollectionMetadataToAllowLoadingByType<New.Person>(store, "People");
WaitForIndexing(store);
}

private void UpdateCollectionMetadataToAllowLoadingByType<T>(IDocumentStore store, string tag)
{
var assemblyName = GetMetadataClrTypeName<T>();
WaitForIndexing(store);
store.DatabaseCommands.UpdateByIndex(
"Raven/DocumentsByEntityName",
new IndexQuery {Query = "Tag:" + tag},
new[]
{
new PatchRequest
{
Type = PatchCommandType.Modify,
Name = "@metadata",
Nested = new[]
{
new PatchRequest
{
Type = PatchCommandType.Set,
Name = "Raven-Clr-Type",
Value = new RavenJValue(assemblyName)
}
}
}
});
}
}

[Migration(1, "CollectionDocumentMigration")]
public class CollectionDocumentMigration : Migration
{
public override void Down()
{
Alter.Collection("People", JoinFirstNameAndLastNameIntoName);
}

public override void Up()
{
Alter.Collection("People", SplitNameToFirstNameAndLastName);
}

private void JoinFirstNameAndLastNameIntoName(RavenJObject obj)
{
var first = obj.Value<string>("FirstName");
var last = obj.Value<string>("LastName");

obj["Name"] = first + " " + last;
obj.Remove("FirstName");
obj.Remove("LastName");
}

private void SplitNameToFirstNameAndLastName(RavenJObject obj)
{
var name = obj.Value<string>("Name");
if (!string.IsNullOrEmpty(name))
{
obj["FirstName"] = name.Split(' ')[0];
obj["LastName"] = name.Split(' ')[1];
}
obj.Remove("Name");
}
}
}
2 changes: 2 additions & 0 deletions RavenMigrations.Tests/RavenMigrations.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CollectionMigrationTests.cs" />
<Compile Include="RunnerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions RavenMigrations.Tests/RunnerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public void Can_call_up_then_down_on_migrations()
Direction = Directions.Down
});

WaitForIndexing(store);
using (var session = store.OpenSession())
{
session.Query<TestDocument, TestDocumentIndex>()
Expand Down
11 changes: 11 additions & 0 deletions RavenMigrations.Tests/app.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="xunit" publicKeyToken="8d05b1bb7a6fdb6c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.9.2.1705" newVersion="1.9.2.1705" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
3 changes: 3 additions & 0 deletions RavenMigrations/Migration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Raven.Client;
using RavenMigrations.Verbs;

namespace RavenMigrations
{
Expand All @@ -8,10 +9,12 @@ public abstract class Migration

public abstract void Up();
public virtual void Down() {}
protected Alter Alter { get; private set; }

public virtual void Setup(IDocumentStore documentStore)
{
DocumentStore = documentStore;
Alter = new Alter(documentStore);
}
}
}
1 change: 1 addition & 0 deletions RavenMigrations/RavenMigrations.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RavenMigrationHelpers.cs" />
<Compile Include="Runner.cs" />
<Compile Include="Verbs\Alter.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
63 changes: 63 additions & 0 deletions RavenMigrations/Verbs/Alter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using Raven.Abstractions.Commands;
using Raven.Abstractions.Data;
using Raven.Client;
using Raven.Json.Linq;

namespace RavenMigrations.Verbs
{
public class Alter
{
public Alter(IDocumentStore documentStore)
{
DocumentStore = documentStore;
}

protected IDocumentStore DocumentStore { get; private set; }

/// <summary>
/// Allows migration of a collection of documents one document at a time.
/// </summary>
/// <param name="tag">The name of the collection.</param>
/// <param name="action">The action to migrate a single document.</param>
/// <param name="pageSize">The page size for batching the documents.</param>
public void Collection(string tag, Action<RavenJObject> action, int pageSize = 128)
{
var count = 0;
do
{
var queryResult = DocumentStore.DatabaseCommands.Query("Raven/DocumentsByEntityName",
new IndexQuery
{
Query = "Tag:" + tag,
PageSize = pageSize,
Start = count
},
null);

if (queryResult.Results.Count == 0) break;

count += queryResult.Results.Count;
var cmds = new List<ICommandData>();
foreach (var result in queryResult.Results)
{
action(result);

var value = result.Value<RavenJObject>("@metadata");
cmds.Add(new PutCommandData
{
Document = result,
Metadata = value,
Key = value.Value<string>("@id"),
});
}

DocumentStore.DatabaseCommands.Batch(cmds.ToArray());
}
while (true);

}

}
}

0 comments on commit 336d47c

Please sign in to comment.