Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'delete-document-feature' into development

  • Loading branch information...
commit 45ed944224f7c0324841f5534a42ec4e007a8f0d 2 parents 961d8bf + 4323676
@dragan dragan authored
View
69 src/SineSignal.Ottoman.Specs/CouchDocumentSessionSpecs.cs
@@ -324,6 +324,75 @@ public void Should_return_populated_entity()
Assert.That(entity1.Login, Is.EqualTo("boblogin"));
}
}
+
+ public class When_deleting_an_entity : ConcernFor<CouchDocumentSession>
+ {
+ private Guid documentId;
+ private Employee entity1;
+ private Type entity1Type;
+ private PropertyInfo identityProperty;
+ private BulkDocsResult[] bulkDocsResults;
+ private ICouchDocumentConvention documentConvention;
+ private ICouchProxy couchProxy;
+ private ICouchDatabase couchDatabase;
+
+ protected override void Given()
+ {
+ documentId = Guid.NewGuid();
+ entity1Type = typeof(Employee);
+ identityProperty = entity1Type.GetProperty("Id");
+
+ documentConvention = Fake<ICouchDocumentConvention>();
+ documentConvention.GetIdentityPropertyFor(entity1Type).Returns(identityProperty);
+
+ var couchDocument = new CouchDocument();
+ couchDocument.Add("_id", documentId.ToString());
+ couchDocument.Add("_rev", "123456");
+ couchDocument.Add("Type", entity1Type.Name);
+ couchDocument.Add("Name", "Bob");
+ couchDocument.Add("Login", "boblogin");
+
+ bulkDocsResults = new BulkDocsResult[1];
+ bulkDocsResults[0] = new BulkDocsResult { Id = documentId.ToString(), Rev = "123456" };
+ couchProxy = Fake<ICouchProxy>();
+ couchProxy.Execute<CouchDocument>(Arg.Any<GetDocumentCommand>()).Returns(couchDocument);
+ couchProxy.Execute<BulkDocsResult[]>(Arg.Any<BulkDocsCommand>()).Returns(bulkDocsResults);
+
+ couchDatabase = Fake<ICouchDatabase>();
+ couchDatabase.Name.Returns("ottoman-test-database");
+ couchDatabase.CouchProxy.Returns(couchProxy);
+ couchDatabase.CouchDocumentConvention.Returns(documentConvention);
+ }
+
+ public override CouchDocumentSession CreateSystemUnderTest()
+ {
+ return new CouchDocumentSession(couchDatabase);
+ }
+
+ protected override void When()
+ {
+ entity1 = Sut.Load<Employee>(documentId.ToString());
+ Sut.Delete<Employee>(entity1);
+ Sut.SaveChanges();
+ }
+
+ [Test]
+ public void Should_call_get_identity_property()
+ {
+ documentConvention.Received().GetIdentityPropertyFor(entity1Type);
+ }
+
+ [Test]
+ public void Should_execute_bulk_docs_command_with_couch_proxy()
+ {
+ couchProxy.Received().Execute<BulkDocsResult[]>(Arg.Is<BulkDocsCommand>(c => {
+ var message = (BulkDocsMessage)c.Message;
+ return c.Route == couchDatabase.Name + "/_bulk_docs" &&
+ c.Operation == HttpMethod.Post &&
+ (message.NonAtomic == false && message.AllOrNothing == false && message.Docs.Length == 1);
+ }));
+ }
+ }
}
public class Employee
View
34 src/SineSignal.Ottoman.Specs/CouchDocumentSpecs.cs
@@ -25,7 +25,7 @@ protected override void Given()
protected override void When()
{
- couchDocument = CouchDocument.Dehydrate(entity1, identityProperty, String.Empty);
+ couchDocument = CouchDocument.Dehydrate(entity1, identityProperty, String.Empty, false);
}
[Test]
@@ -56,7 +56,7 @@ protected override void Given()
protected override void When()
{
- couchDocument = CouchDocument.Dehydrate(entity1, identityProperty, revision);
+ couchDocument = CouchDocument.Dehydrate(entity1, identityProperty, revision, false);
}
[Test]
@@ -69,5 +69,35 @@ public void Should_create_couch_document_with_revision()
Assert.That(couchDocument["Login"], Is.EqualTo(entity1.Login));
}
}
+
+ public class When_dehydrating_an_entity_into_a_couch_document_that_is_marked_for_deletion : StaticConcern
+ {
+ private Employee entity1;
+ private Type entity1Type;
+ private PropertyInfo identityProperty;
+ private string revision;
+ private CouchDocument couchDocument;
+
+ protected override void Given()
+ {
+ entity1 = new Employee { Id = Guid.NewGuid(), Name = "Bob", Login = "boblogin" };
+ entity1Type = entity1.GetType();
+ identityProperty = entity1Type.GetProperty("Id");
+ revision = "abc123";
+ }
+
+ protected override void When()
+ {
+ couchDocument = CouchDocument.Dehydrate(entity1, identityProperty, revision, true);
+ }
+
+ [Test]
+ public void Should_create_couch_document_with_deleted_key()
+ {
+ Assert.That(couchDocument["_id"], Is.EqualTo(entity1.Id));
+ Assert.That(couchDocument["_rev"], Is.EqualTo(revision));
+ Assert.That(couchDocument["_deleted"], Is.True);
+ }
+ }
}
}
View
31 src/SineSignal.Ottoman/CouchDocument.cs
@@ -7,24 +7,33 @@ namespace SineSignal.Ottoman
{
internal class CouchDocument : Dictionary<string, object>, IDictionary<string, object>
{
- public static CouchDocument Dehydrate(object entity, PropertyInfo identityProperty, string revision)
+ public static CouchDocument Dehydrate(object entity, PropertyInfo identityProperty, string revision, bool delete)
{
var couchDocument = new CouchDocument();
var entityType = entity.GetType();
- couchDocument["Type"] = entityType.Name;
-
- if (revision != String.Empty)
+ if (delete)
+ {
+ couchDocument["_id"] = entityType.GetProperty(identityProperty.Name).GetValue(entity, null);
couchDocument["_rev"] = revision;
-
- foreach (PropertyInfo property in entityType.GetProperties().Where(p => p.CanRead))
+ couchDocument["_deleted"] = true;
+ }
+ else
{
- var key = property.Name;
- if (key == identityProperty.Name)
- key = "_id";
+ couchDocument["Type"] = entityType.Name;
- var propertyValue = property.GetValue(entity, null);
- couchDocument[key] = propertyValue;
+ if (revision != String.Empty)
+ couchDocument["_rev"] = revision;
+
+ foreach (PropertyInfo property in entityType.GetProperties().Where(p => p.CanRead))
+ {
+ var key = property.Name;
+ if (key == identityProperty.Name)
+ key = "_id";
+
+ var propertyValue = property.GetValue(entity, null);
+ couchDocument[key] = propertyValue;
+ }
}
return couchDocument;
View
37 src/SineSignal.Ottoman/CouchDocumentSession.cs
@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
using SineSignal.Ottoman.Commands;
using SineSignal.Ottoman.Exceptions;
@@ -15,12 +18,14 @@ public class CouchDocumentSession : ICouchDocumentSession
private Dictionary<string, object> IdentityMap { get; set; }
private Dictionary<object, EntityMetadata> EntityMetadataMap { get; set; }
+ private HashSet<object> DeletedEntities { get; set; }
public CouchDocumentSession(ICouchDatabase couchDatabase)
{
CouchDatabase = couchDatabase;
IdentityMap = new Dictionary<string, object>();
EntityMetadataMap = new Dictionary<object, EntityMetadata>();
+ DeletedEntities = new HashSet<object>();
}
public void Store(object entity)
@@ -70,15 +75,41 @@ public T Load<T>(string id) where T : new()
return StalkEntity<T>(couchDocument);
}
+ public void Delete<T>(T entity)
+ {
+ if (EntityMetadataMap.ContainsKey(entity) == false)
+ throw new InvalidOperationException(String.Format("{0} is not associated with the current couch document session, cannot delete unknown entity.", entity));
+
+ DeletedEntities.Add(entity);
+ }
+
public void SaveChanges()
{
var docs = new List<CouchDocument>();
var entities = new List<object>();
+
+ foreach (var entity in DeletedEntities)
+ {
+ EntityMetadata entityMetadata;
+ if (EntityMetadataMap.TryGetValue(entity, out entityMetadata))
+ {
+ EntityMetadataMap.Remove(entity);
+ IdentityMap.Remove(entityMetadata.Key);
+
+ Type entityType = entity.GetType();
+ PropertyInfo identityProperty = CouchDatabase.CouchDocumentConvention.GetIdentityPropertyFor(entityType);
+
+ docs.Add(CouchDocument.Dehydrate(entity, identityProperty, entityMetadata.Revision, true));
+ entities.Add(entity);
+ }
+ }
+ DeletedEntities.Clear();
+
foreach (var entity in EntityMetadataMap.Where(pair => IsEntityDirty(pair.Key, pair.Value)))
{
Type entityType = entity.Key.GetType();
PropertyInfo identityProperty = CouchDatabase.CouchDocumentConvention.GetIdentityPropertyFor(entityType);
- docs.Add(CouchDocument.Dehydrate(entity.Key, identityProperty, entity.Value.Revision));
+ docs.Add(CouchDocument.Dehydrate(entity.Key, identityProperty, entity.Value.Revision, false));
entities.Add(entity.Key);
}
@@ -120,7 +151,9 @@ private static object GetIdentityValueFor(object entity, PropertyInfo identityPr
private bool IsEntityDirty(object entity, EntityMetadata entityMetadata)
{
- return entity.Equals(entityMetadata.OriginalEntity) == false;
+ // TODO: Need to find a better way to tell if the entity is dirty
+ //return entity.Equals(entityMetadata.OriginalEntity) == false;
+ return true;
}
private T StalkEntity<T>(CouchDocument couchDocument) where T : new()
View
1  src/SineSignal.Ottoman/ICouchDocumentSession.cs
@@ -4,6 +4,7 @@ public interface ICouchDocumentSession
{
void Store(object entity);
T Load<T>(string id) where T : new();
+ void Delete<T>(T entity);
void SaveChanges();
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.