Skip to content

Commit

Permalink
Introduce MongoDB.Extensions.Migration (#62)
Browse files Browse the repository at this point in the history
Add fist version of Mongo.Extensions.Migration for performing migrations with MongoDB
  • Loading branch information
TimHolzherr authored Jul 20, 2022
1 parent 7bdccc0 commit 9452f47
Show file tree
Hide file tree
Showing 43 changed files with 1,180 additions and 5 deletions.
8 changes: 8 additions & 0 deletions samples/Migration/Customer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using MongoDB.Extensions.Migration;

namespace Migration;

public record Customer(string Id, string Name) : IVersioned
{
public int Version { get; set; }
}
19 changes: 19 additions & 0 deletions samples/Migration/ExampleMigration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using MongoDB.Bson;
using MongoDB.Extensions.Migration;

namespace Migration;

public class ExampleMigration : IMigration
{
public int Version => 1;

public void Up(BsonDocument document)
{
document["Name"] += " Migrated up to 1";
}

public void Down(BsonDocument document)
{
document["Name"] += " Migrated down to 0";
}
}
14 changes: 14 additions & 0 deletions samples/Migration/Migration.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.15.1" />
<PackageReference Include="MongoDB.Extensions.Migration" Version="1.3.0-preview1" />
</ItemGroup>

</Project>
21 changes: 21 additions & 0 deletions samples/Migration/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Migration;
using MongoDB.Extensions.Migration;
using MongoDB.Driver;

var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddSingleton(_ => new MongoClient("mongodb://localhost:27017"))
.AddTransient<Repository>();

var app = builder.Build();

app.UseMongoMigration(m => m
.ForEntity<Customer>(e => e
.AtVersion(1)
.WithMigration(new ExampleMigration())));

app.MapGet("/customer/{id}", (string id, Repository repo) => repo.GetAsync(id));
app.MapPost("/customer/", (Customer customer, Repository repo) => repo.AddAsync(customer));

app.Run();
20 changes: 20 additions & 0 deletions samples/Migration/Repository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using MongoDB.Driver;
using MongoDB.Driver.Linq;

namespace Migration;

public class Repository
{
private readonly IMongoCollection<Customer> _collection;

public Repository(MongoClient client)
{
var database = client.GetDatabase("Example1");
_collection = database.GetCollection<Customer>("customer");
}

public Task AddAsync(Customer customer) => _collection.InsertOneAsync(customer);

public Task<Customer> GetAsync(string id) => _collection.AsQueryable()
.SingleOrDefaultAsync(c => c.Id == id);
}
8 changes: 8 additions & 0 deletions samples/Migration/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions samples/Migration/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
6 changes: 6 additions & 0 deletions samples/MongoDB.Extensions.Samples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SimpleBlog", "SimpleBlog",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Host", "Context\Host\Host.csproj", "{0CCED088-DBB6-4DA2-8DFC-D9968EEBB9FA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migration", "Migration\Migration.csproj", "{8226313B-FAC9-4D0F-AEE8-424DD310BBFB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -43,6 +45,10 @@ Global
{0CCED088-DBB6-4DA2-8DFC-D9968EEBB9FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0CCED088-DBB6-4DA2-8DFC-D9968EEBB9FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CCED088-DBB6-4DA2-8DFC-D9968EEBB9FA}.Release|Any CPU.Build.0 = Release|Any CPU
{8226313B-FAC9-4D0F-AEE8-424DD310BBFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8226313B-FAC9-4D0F-AEE8-424DD310BBFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8226313B-FAC9-4D0F-AEE8-424DD310BBFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8226313B-FAC9-4D0F-AEE8-424DD310BBFB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
88 changes: 88 additions & 0 deletions src/Migration.Tests/Integration/Scenario1/MigrateDownTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Extensions.Migration;
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Migration.Tests;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Squadron;
using Xunit;

namespace MongoMigrationTest.Integration.Scenario1;

[Collection("SharedMongoDbCollection")]
public class MigrateDownTests
{
readonly IMongoCollection<TestEntityForDown> _typedCollection;
readonly IMongoCollection<BsonDocument> _untypedCollection;

public MigrateDownTests(MongoResource resource)
{
RegisterMongoMigrations();
IMongoDatabase database = resource.Client.GetDatabase("Scenario1-down");
_typedCollection = database.GetCollection<TestEntityForDown>("TestEntityForDown");
_untypedCollection = database.GetCollection<BsonDocument>("TestEntityForDown");
}

static void RegisterMongoMigrations()
{
MigrationOption options = new MigrationOptionBuilder()
.ForEntity<TestEntityForDown>(o => o.AtVersion(0)
.WithMigration(new TestMigration1())
.WithMigration(new TestMigration2())
.WithMigration(new TestMigration3()))
.Build();
var context = new MigrationContext(options, NullLoggerFactory.Instance);

BsonSerializer.RegisterSerializationProvider(new MigrationSerializerProvider(context));
}

[Fact]
public async Task Scenario1_AddRetrieve_NoMigration()
{
// Arrange
const string input = "Bar";
await _typedCollection.InsertOneAsync(new TestEntityForDown("1", input));

// Act
TestEntityForDown result = await _typedCollection.AsQueryable()
.SingleOrDefaultAsync(c => c.Id == "1");

// Assert
result.Foo.Should().Be(input);
}

[Fact]
public async Task Scenario1_RetrieveAtVersion3_MigratedDownTo0()
{
// Arrange
await _untypedCollection.InsertOneAsync(new BsonDocument(new Dictionary<string, object>
{ ["_id"] = "id0", ["Foo"] = "Bar", ["Version"] = 3 }));

// Act
TestEntityForDown result = await _typedCollection.AsQueryable()
.SingleOrDefaultAsync(c => c.Id == "id0");

// Assert
result.Foo.Should().Be("Bar Migrated Down to 2 Migrated Down to 1 Migrated Down to 0");
}

[Fact]
public async Task Scenario1_RetrieveAtVersion2_MigratedToVersion3()
{
// Arrange
await _untypedCollection.InsertOneAsync(new BsonDocument(new Dictionary<string, object>
{ ["_id"] = "id1", ["Foo"] = "Bar", ["Version"] = 1 }));

// Act
TestEntityForDown result = await _typedCollection.AsQueryable()
.SingleOrDefaultAsync(c => c.Id == "id1");

// Assert
result.Foo.Should().Be("Bar Migrated Down to 0");
}

}
98 changes: 98 additions & 0 deletions src/Migration.Tests/Integration/Scenario1/MigrateUpTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Extensions.Migration;
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Migration.Tests;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using Xunit;
using MongoDB.Driver.Linq;
using Squadron;

namespace MongoMigrationTest.Integration.Scenario1;

[Collection("SharedMongoDbCollection")]
public class MigrateUpTests
{
readonly IMongoCollection<TestEntityForUp> _typedCollection;
readonly IMongoCollection<BsonDocument> _untypedCollection;

public MigrateUpTests(MongoResource resource)
{
RegisterMongoMigrations();
IMongoDatabase database = resource.Client.GetDatabase("Scenario1-up");
_typedCollection = database.GetCollection<TestEntityForUp>("TestEntityForUp");
_untypedCollection = database.GetCollection<BsonDocument>("TestEntityForUp");
}

static void RegisterMongoMigrations()
{
MigrationOption options = new MigrationOptionBuilder()
.ForEntity<TestEntityForUp>(o => o
.WithMigration(new TestMigration1())
.WithMigration(new TestMigration2())
.WithMigration(new TestMigration3()))
.Build();
var context = new MigrationContext(options, NullLoggerFactory.Instance);

BsonSerializer.RegisterSerializationProvider(new MigrationSerializerProvider(context));
}

[Fact]
public async Task Scenario1_AddRetrieve_NoMigration()
{
// Arrange
const string input = "Bar";
await _typedCollection.InsertOneAsync(new TestEntityForUp("1", input));

// Act
var result = await _typedCollection.AsQueryable().SingleOrDefaultAsync(c => c.Id == "1");

// Assert
result.Foo.Should().Be(input);
}

[Fact]
public async Task Scenario1_RetrieveWithoutVersion_MigratedToNewestVersion()
{
// Arrange
await _untypedCollection.InsertOneAsync(new BsonDocument(new Dictionary<string, object>
{ ["_id"] = "2", ["Foo"] = "Bar" }));

// Act
TestEntityForUp result = await _typedCollection.AsQueryable().SingleOrDefaultAsync(c => c.Id == "2");

// Assert
result.Foo.Should().Be("Bar Migrated Up to 1 Migrated Up to 2 Migrated Up to 3");
}

[Fact]
public async Task Scenario1_RetrieveAtNewUnknownVersion_NoMigration()
{
// Arrange
await _untypedCollection.InsertOneAsync(new BsonDocument(new Dictionary<string, object>
{ ["_id"] = "3", ["Foo"] = "Bar", ["Version"] = 4 }));

// Act
TestEntityForUp result = await _typedCollection.AsQueryable().SingleOrDefaultAsync(c => c.Id == "3");

// Assert
result.Foo.Should().Be("Bar");
}

[Fact]
public async Task Scenario1_RetrieveAtVersion2_MigratedToVersion3()
{
// Arrange
await _untypedCollection.InsertOneAsync(new BsonDocument(new Dictionary<string, object>
{ ["_id"] = "4", ["Foo"] = "Bar", ["Version"] = 2 }));

// Act
TestEntityForUp result = await _typedCollection.AsQueryable().SingleOrDefaultAsync(c => c.Id == "4");

// Assert
result.Foo.Should().Be("Bar Migrated Up to 3");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using MongoDB.Extensions.Migration;

namespace MongoMigrationTest.Integration.Scenario1;

public record TestEntityForDown(string Id, string Foo) : IVersioned
{
public int Version { get; set; }
}
8 changes: 8 additions & 0 deletions src/Migration.Tests/Integration/Scenario1/TestEntityForUp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using MongoDB.Extensions.Migration;

namespace MongoMigrationTest.Integration.Scenario1;

public record TestEntityForUp(string Id, string Foo) : IVersioned
{
public int Version { get; set; }
}
Loading

0 comments on commit 9452f47

Please sign in to comment.