Skip to content

Commit

Permalink
Merge pull request #26 from sbmako/5.2.4-patch
Browse files Browse the repository at this point in the history
added saga data change detection and removed subscription dependency on IHaveDocumentVersion
  • Loading branch information
sbmako authored Oct 9, 2016
2 parents 0d8dc04 + 0c2dbbd commit e299f4d
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 225 deletions.
2 changes: 1 addition & 1 deletion packaging/nuget/NServiceBus.MongoDB.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>NServiceBus.MongoDB</id>
<title>NServiceBus MongoDB</title>
<version>5.2.4</version>
<version>5.2.5</version>
<authors>Carlos Sandoval</authors>
<owners>SharkByte Software</owners>
<licenseUrl>https://github.com/sbmako/NServiceBus.MongoDB/blob/master/LICENSE</licenseUrl>
Expand Down
Binary file modified src/.nuget/NuGet.exe
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion
public virtual Guid SomeId { get; set; }

public int DocumentVersion { get; set; }

public int ETag { get; set; }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion
public virtual Guid SomeId { get; set; }

public int DocumentVersion { get; set; }
public int ETag { get; set; }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion
public virtual Guid SomeId { get; set; }

public int DocumentVersion { get; set; }
public int ETag { get; set; }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion
public virtual string KeyValue { get; set; }

public int DocumentVersion { get; set; }
public int ETag { get; set; }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion
public virtual Guid SomeId { get; set; }

public int DocumentVersion { get; set; }
public int ETag { get; set; }
}
}

Expand Down
1 change: 1 addition & 0 deletions src/NServiceBus.MongoDB.Tests/Issues/Issue_16.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@ public sealed class DeviceCommandSagaState : IContainSagaData, IHaveDocumentVers

//IHaveDocumentVersion properties
public int DocumentVersion { get; set; }
public int ETag { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,40 @@ public void UpdatingSagaWithoutDocumentVersion(
sut.Invoking(s => s.Update(sagaData)).ShouldThrow<InvalidOperationException>();
}

[Theory, IntegrationTest]
[AutoDatabase]
public void UpdatingSagaWithNoChangesShouldNotUpdateVersion(
MongoSagaPersister sut,
MongoDatabaseFactory factory,
SagaWithoutUniqueProperties sagaData)
{
sut.Save(sagaData);
var saga1 = factory.RetrieveSagaData(sagaData);

sut.Update(saga1);

var saga2 = factory.RetrieveSagaData(sagaData);
saga2.DocumentVersion.Should().Be(saga1.DocumentVersion);
}

[Theory, IntegrationTest]
[AutoDatabase]
public void UpdatingSagaWithChangesShouldUpdateVersion(
MongoSagaPersister sut,
MongoDatabaseFactory factory,
SagaWithoutUniqueProperties sagaData)
{
sut.Save(sagaData);
var saga1 = factory.RetrieveSagaData(sagaData);

saga1.UniqueProperty = "NewValue";
sut.Update(saga1);

var saga2 = factory.RetrieveSagaData(sagaData);
saga2.DocumentVersion.Should().Be(saga1.DocumentVersion + 1);
saga2.UniqueProperty.Should().Be(saga1.UniqueProperty);
}

[Theory, IntegrationTest]
[AutoDatabase]
public void CompletingSagaShouldRemoveDocument(
Expand Down
5 changes: 5 additions & 0 deletions src/NServiceBus.MongoDB/ContainMongoSagaData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@ public abstract class ContainMongoSagaData : ContainSagaData, IHaveDocumentVersi
/// Gets or sets the document version.
/// </summary>
public int DocumentVersion { get; set; }

/// <summary>
/// Gets or sets the e tag.
/// </summary>
public int ETag { get; set; }
}
}
219 changes: 114 additions & 105 deletions src/NServiceBus.MongoDB/Extensions/DocumentVersionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,105 +1,114 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DocumentVersionExtensions.cs" company="SharkByte Software">
// The MIT License (MIT)
//
// Copyright (c) 2015 SharkByte Software
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
// <summary>
// Defines the DocumentVersionExtensions type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace NServiceBus.MongoDB.Extensions
{
using System;
using System.Diagnostics.Contracts;
using System.Linq;
using global::MongoDB.Bson;
using global::MongoDB.Driver;
using global::MongoDB.Driver.Builders;

using NServiceBus.MongoDB.Internals;
using NServiceBus.MongoDB.SubscriptionPersister;
using NServiceBus.Saga;

internal static class DocumentVersionExtensions
{
public static IMongoQuery MongoUpdateQuery(this IContainSagaData saga)
{
Contract.Requires(saga != null);
Contract.Ensures(Contract.Result<IMongoQuery>() != null);

var versionedDocument = saga as IHaveDocumentVersion;

if (versionedDocument == null)
{
throw new InvalidOperationException(
string.Format("Saga type {0} does not implement IHaveDocumentVersion", saga.GetType().Name));
}

return
Query.And(
Query.EQ("_id", saga.Id),
Query.EQ(MongoPersistenceConstants.VersionPropertyName, versionedDocument.DocumentVersion))
.AssumedNotNull();
}

public static IMongoUpdate MongoUpdate<T>(this T saga) where T : IContainSagaData
{
Contract.Requires(saga != null);
Contract.Ensures(Contract.Result<IMongoUpdate>() != null);

var classMap = saga.ToBsonDocument();

var versionedDocument = saga as IHaveDocumentVersion;
if (versionedDocument == null)
{
return Update.Replace(saga).AssumedNotNull();
}

classMap.Remove("_id");
classMap.Remove(MongoPersistenceConstants.VersionPropertyName);
var updateBuilder = Update.Inc(MongoPersistenceConstants.VersionPropertyName, 1);

classMap.ToList().ForEach(f => updateBuilder.Set(f.Name, f.Value));

return updateBuilder.AssumedNotNull();
}

public static IMongoQuery MongoUpdateQuery(this Subscription subscription)
{
Contract.Requires(subscription != null);
Contract.Ensures(Contract.Result<IMongoQuery>() != null);

return
Query.And(
Query<Subscription>.EQ(s => s.Id, subscription.Id),
Query<Subscription>.EQ(s => s.DocumentVersion, subscription.DocumentVersion)).AssumedNotNull();
}

public static IMongoUpdate MongoUpdate(this Subscription subscription)
{
Contract.Requires(subscription != null);
Contract.Ensures(Contract.Result<IMongoUpdate>() != null);

return Update.Replace(subscription).AssumedNotNull();
}
}
}
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DocumentVersionExtensions.cs" company="SharkByte Software">
// The MIT License (MIT)
//
// Copyright (c) 2015 SharkByte Software
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
// <summary>
// Defines the DocumentVersionExtensions type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace NServiceBus.MongoDB.Extensions
{
using System;
using System.Diagnostics.Contracts;
using System.Linq;
using global::MongoDB.Bson;
using global::MongoDB.Driver;
using global::MongoDB.Driver.Builders;

using NServiceBus.MongoDB.Internals;
using NServiceBus.MongoDB.SubscriptionPersister;
using NServiceBus.Saga;

internal static class DocumentVersionExtensions
{
public static IMongoQuery MongoUpdateQuery(this IContainSagaData saga)
{
Contract.Requires(saga != null);
Contract.Ensures(Contract.Result<IMongoQuery>() != null);

var versionedDocument = saga as IHaveDocumentVersion;

if (versionedDocument == null)
{
throw new InvalidOperationException(
string.Format("Saga type {0} does not implement IHaveDocumentVersion", saga.GetType().Name));
}

return
Query.And(
Query.EQ("_id", saga.Id),
Query.EQ(MongoPersistenceConstants.VersionPropertyName, versionedDocument.DocumentVersion))
.AssumedNotNull();
}

public static IMongoUpdate MongoUpdate<T>(this T saga) where T : IContainSagaData
{
Contract.Requires(saga != null);
Contract.Ensures(Contract.Result<IMongoUpdate>() != null);

var classMap = saga.ToBsonDocument();

var versionedDocument = saga as IHaveDocumentVersion;
if (versionedDocument == null)
{
return Update.Replace(saga).AssumedNotNull();
}

classMap.Remove("_id");
classMap.Remove(MongoPersistenceConstants.VersionPropertyName);
var updateBuilder = Update.Inc(MongoPersistenceConstants.VersionPropertyName, 1);

classMap.ToList().ForEach(f => updateBuilder.Set(f.Name, f.Value));

return updateBuilder.AssumedNotNull();
}

public static IMongoQuery MongoUpdateQuery(this Subscription subscription)
{
Contract.Requires(subscription != null);
Contract.Ensures(Contract.Result<IMongoQuery>() != null);

return Query<Subscription>.EQ(s => s.Id, subscription.Id).AssumedNotNull();
}

public static IMongoUpdate MongoUpdate(this Subscription subscription)
{
Contract.Requires(subscription != null);
Contract.Ensures(Contract.Result<IMongoUpdate>() != null);

return Update.Replace(subscription).AssumedNotNull();
}

public static int ComputeETag<T>(this T sagaData) where T : IContainSagaData
{
Contract.Requires(sagaData != null);

var bsonDocument = sagaData.ToBsonDocument();

bsonDocument.Remove(MongoPersistenceConstants.VersionPropertyName);
bsonDocument.Remove(MongoPersistenceConstants.ETagPropertyName);

return bsonDocument.GetHashCode();
}
}
}
5 changes: 5 additions & 0 deletions src/NServiceBus.MongoDB/IHaveDocumentVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,10 @@ public interface IHaveDocumentVersion
/// Gets or sets the document version.
/// </summary>
int DocumentVersion { get; set; }

/// <summary>
/// Gets or sets the e tag.
/// </summary>
int ETag { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ internal static class MongoPersistenceConstants

public const string VersionPropertyName = "DocumentVersion";

public const string ETagPropertyName = "ETag";

public const string OwningTimeoutManagerAndTimeName = "OwningTimeoutManagerAndTime";

public const string OwningTimeoutManagerAndSagaIdAndTimeName = "OwningTimeoutManagerAndSagaIdAndTime";
Expand Down
2 changes: 1 addition & 1 deletion src/NServiceBus.MongoDB/NServiceBus.MongoDB.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\DebugContracts\</OutputPath>
<DefineConstants>CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<DebugType>full</DebugType>
<RunCodeAnalysis>false</RunCodeAnalysis>
<ErrorReport>prompt</ErrorReport>
Expand Down
15 changes: 14 additions & 1 deletion src/NServiceBus.MongoDB/SagaPersister/MongoSagaPersister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,17 @@ public void Save(IContainSagaData saga)
{
var sagaTypeName = saga.GetType().Name;

if (!(saga is IHaveDocumentVersion))
var sagaDataWithVersion = saga as IHaveDocumentVersion;

if (sagaDataWithVersion == null)
{
throw new InvalidOperationException(
string.Format("Saga type {0} does not implement IHaveDocumentVersion", sagaTypeName));
}

sagaDataWithVersion.DocumentVersion = 0;
sagaDataWithVersion.ETag = saga.ComputeETag();

var uniqueProperty = UniqueAttribute.GetUniqueProperty(saga);
if (uniqueProperty.HasValue)
{
Expand All @@ -96,6 +101,14 @@ public void Save(IContainSagaData saga)
/// <param name="saga">The saga entity to updated.</param>
public void Update(IContainSagaData saga)
{
var newETag = saga.AssumedNotNull().ComputeETag();

var versionedDocument = (IHaveDocumentVersion)saga;
if (versionedDocument.ETag == newETag)
{
return;
}

var collection = this.mongoDatabase.GetCollection(saga.GetType().Name);

var query = saga.MongoUpdateQuery();
Expand Down
Loading

0 comments on commit e299f4d

Please sign in to comment.