Commit dd9cd1d

mokhan <mokhan@ce5e1baf-6525-42e4-a1b2-857ea38da20a>
2009-04-04 17:26:38
flushing out the rest of the new unit of work.
git-svn-id: https://svn.xp-dev.com/svn/mokhan-mo.money@136 ce5e1baf-6525-42e4-a1b2-857ea38da20a
1 parent 682db4c
trunk/product/MyMoney/Infrastructure/transactions2/ChangeTracker.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.Linq;
+using MoMoney.Utility.Extensions;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public class ChangeTracker<T> : IChangeTracker<T>
+    {
+        readonly ITrackerEntryMapper<T> mapper;
+        readonly IStatementRegistry registry;
+        readonly IList<ITrackerEntry<T>> items;
+
+        public ChangeTracker(ITrackerEntryMapper<T> mapper, IStatementRegistry registry)
+        {
+            this.mapper = mapper;
+            this.registry = registry;
+            items = new List<ITrackerEntry<T>>();
+        }
+
+        public void register(T entity)
+        {
+            items.Add(mapper.map_from(entity));
+        }
+
+        public void commit_to(IDatabase database)
+        {
+            items.each(x => commit(x, database));
+        }
+
+        public bool is_dirty()
+        {
+            return items.Count(x => x.contains_changes()) > 0;
+        }
+
+        public void Dispose()
+        {
+            items.Clear();
+        }
+
+        void commit(ITrackerEntry<T> entry, IDatabase database)
+        {
+            if (entry.contains_changes()) database.apply(registry.prepare_command_for(entry.current));
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/ChangeTrackerFactory.cs
@@ -0,0 +1,21 @@
+using MoMoney.Infrastructure.Container;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public class ChangeTrackerFactory : IChangeTrackerFactory
+    {
+        readonly IStatementRegistry statement_registry;
+        readonly IDependencyRegistry registry;
+
+        public ChangeTrackerFactory(IStatementRegistry statement_registry, IDependencyRegistry registry)
+        {
+            this.statement_registry = statement_registry;
+            this.registry = registry;
+        }
+
+        public IChangeTracker<T> create_for<T>()
+        {
+            return new ChangeTracker<T>(registry.get_a<ITrackerEntryMapper<T>>(), statement_registry);
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/ChangeTrackerFactorySpecs.cs
@@ -0,0 +1,20 @@
+using developwithpassion.bdd.contexts;
+using MoMoney.Domain.Core;
+using MoMoney.Testing.spechelpers.contexts;
+using MoMoney.Testing.spechelpers.core;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public class ChangeTrackerFactorySpecs
+    {
+    }
+
+    public class when_creating_a_change_tracker_for_an_item : concerns_for<IChangeTrackerFactory, ChangeTrackerFactory>
+    {
+        it should_return_a_new_tracker = () => { result.should_not_be_null(); };
+
+        because b = () => { result = sut.create_for<IEntity>(); };
+
+        static IChangeTracker<IEntity> result;
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/ChangeTrackerSpecs.cs
@@ -0,0 +1,100 @@
+using developwithpassion.bdd.contexts;
+using MoMoney.Domain.Core;
+using MoMoney.Testing.MetaData;
+using MoMoney.Testing.spechelpers.contexts;
+using MoMoney.Testing.spechelpers.core;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public class ChangeTrackerSpecs
+    {
+    }
+
+    [Concern(typeof (ChangeTracker<IEntity>))]
+    public abstract class behaves_like_change_tracker : concerns_for<IChangeTracker<IEntity>, ChangeTracker<IEntity>>
+    {
+        context c = () =>
+                        {
+                            mapper = the_dependency<ITrackerEntryMapper<IEntity>>();
+                            registry = the_dependency<IStatementRegistry>();
+                        };
+
+        protected static ITrackerEntryMapper<IEntity> mapper;
+        protected static IStatementRegistry registry;
+    }
+
+    public class when_commit_that_changes_made_to_an_item : behaves_like_change_tracker
+    {
+        it should_save_the_changes_to_the_database = () => database.was_told_to(x => x.apply(statement));
+
+        context c = () =>
+                        {
+                            item = an<IEntity>();
+                            statement = an<IStatement>();
+                            database = an<IDatabase>();
+                            var entry = an<ITrackerEntry<IEntity>>();
+
+                            when_the(mapper).is_told_to(x => x.map_from(item)).it_will_return(entry);
+                            when_the(entry).is_told_to(x => x.contains_changes()).it_will_return(true);
+                            when_the(entry).is_told_to(x => x.current).it_will_return(item);
+                            when_the(registry).is_told_to(x => x.prepare_command_for(item)).it_will_return(statement);
+                        };
+
+        because b = () =>
+                        {
+                            sut.register(item);
+                            sut.commit_to(database);
+                        };
+
+        static IEntity item;
+        static IDatabase database;
+        static IStatement statement;
+    }
+
+    public class when_checking_if_there_are_changes_and_there_are : behaves_like_change_tracker
+    {
+        it should_tell_the_truth = () => result.should_be_true();
+
+        context c = () =>
+                        {
+                            item = an<IEntity>();
+                            var registration = an<ITrackerEntry<IEntity>>();
+
+                            when_the(mapper).is_told_to(x => x.map_from(item)).it_will_return(registration);
+                            when_the(registration).is_told_to(x => x.contains_changes()).it_will_return(true);
+                            when_the(registration).is_told_to(x => x.current).it_will_return(item);
+                        };
+
+        because b = () =>
+                        {
+                            sut.register(item);
+                            result = sut.is_dirty();
+                        };
+
+        static bool result;
+        static IEntity item;
+    }
+
+    public class when_checking_if_there_are_changes_and_there_are_not : behaves_like_change_tracker
+    {
+        it should_tell_the_truth = () => result.should_be_false();
+
+        context c = () =>
+                        {
+                            item = an<IEntity>();
+                            var entry = an<ITrackerEntry<IEntity>>();
+
+                            when_the(mapper).is_told_to(x => x.map_from(item)).it_will_return(entry);
+                            when_the(entry).is_told_to(x => x.contains_changes()).it_will_return(false);
+                        };
+
+        because b = () =>
+                        {
+                            sut.register(item);
+                            result = sut.is_dirty();
+                        };
+
+        static bool result;
+        static IEntity item;
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/Database.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using MoMoney.Domain.Core;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public class Database : IDatabase
+    {
+        public IEnumerable<T> fetch_all<T>() where T : IEntity
+        {
+            throw new NotImplementedException();
+        }
+
+        public void apply(IStatement statement)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/IChangeTracker.cs
@@ -1,3 +1,5 @@
+using System;
+
 namespace MoMoney.Infrastructure.transactions2
 {
     public interface IChangeTracker
@@ -6,7 +8,7 @@ namespace MoMoney.Infrastructure.transactions2
         void commit_to(IDatabase database);
     }
 
-    public interface IChangeTracker<T> : IChangeTracker
+    public interface IChangeTracker<T> : IChangeTracker, IDisposable
     {
         void register(T value);
     }
trunk/product/MyMoney/Infrastructure/transactions2/IStatementRegistry.cs
@@ -1,9 +1,16 @@
+using System;
+
 namespace MoMoney.Infrastructure.transactions2
 {
     public interface IStatementRegistry
     {
+        [Obsolete]
         IStatement prepare_insert_statement_for<T>(T entity);
+
+        [Obsolete]
         IStatement prepare_update_statement_for<T>(T entity);
+
         IStatement prepare_delete_statement_for<T>(T entity);
+        IStatement prepare_command_for<T>(T entity);
     }
 }
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/ITrackerEntry.cs
@@ -0,0 +1,8 @@
+namespace MoMoney.Infrastructure.transactions2
+{
+    public interface ITrackerEntry<T>
+    {
+        T current { get; }
+        bool contains_changes();
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/ITrackerEntryMapper.cs
@@ -0,0 +1,8 @@
+using MoMoney.Utility.Core;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public interface ITrackerEntryMapper<T> : IMapper<T, ITrackerEntry<T>>
+    {
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/SessionFactory.cs
@@ -0,0 +1,27 @@
+using MoMoney.Utility.Core;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public interface ISessionFactory : IFactory<ISession>
+    {
+    }
+
+    public class SessionFactory : ISessionFactory
+    {
+        readonly IDatabase database;
+        readonly IStatementRegistry registry;
+        readonly IChangeTrackerFactory factory;
+
+        public SessionFactory(IDatabase database, IStatementRegistry registry, IChangeTrackerFactory factory)
+        {
+            this.database = database;
+            this.registry = registry;
+            this.factory = factory;
+        }
+
+        public ISession create()
+        {
+            return new Session(new Transaction(registry, database, factory), database);
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/SessionFactorySpecs.cs
@@ -0,0 +1,19 @@
+using developwithpassion.bdd.contexts;
+using MoMoney.Testing.spechelpers.contexts;
+using MoMoney.Testing.spechelpers.core;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public class SessionFactorySpecs
+    {
+    }
+
+    public class when_creating_a_new_session : concerns_for<ISessionFactory, SessionFactory>
+    {
+        it should_return_a_new_session = () => result.should_not_be_null();
+
+        because b = () => { result = sut.create(); };
+
+        static ISession result;
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/StatementRegistry.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace MoMoney.Infrastructure.transactions2
+{
+    public class StatementRegistry : IStatementRegistry
+    {
+        public IStatement prepare_insert_statement_for<T>(T entity)
+        {
+            throw new NotImplementedException();
+        }
+
+        public IStatement prepare_update_statement_for<T>(T entity)
+        {
+            throw new NotImplementedException();
+        }
+
+        public IStatement prepare_delete_statement_for<T>(T entity)
+        {
+            throw new NotImplementedException();
+        }
+
+        public IStatement prepare_command_for<T>(T entity)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}
\ No newline at end of file
trunk/product/MyMoney/Infrastructure/transactions2/Transaction.cs
@@ -1,8 +1,6 @@
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using MoMoney.Domain.Core;
-using MoMoney.Infrastructure.Extensions;
 using MoMoney.Utility.Extensions;
 
 namespace MoMoney.Infrastructure.transactions2
@@ -25,7 +23,7 @@ namespace MoMoney.Infrastructure.transactions2
         readonly List<IEntity> transients;
         readonly List<IEntity> dirty;
         readonly List<IEntity> to_be_deleted;
-        IDictionary<Type, IChangeTracker> change_trackers;
+        readonly IDictionary<Type, IChangeTracker> change_trackers;
 
         public Transaction(IStatementRegistry registry, IDatabase database, IChangeTrackerFactory factory)
         {
@@ -76,12 +74,7 @@ namespace MoMoney.Infrastructure.transactions2
 
         IChangeTracker<T> get_change_tracker_for<T>() where T : IEntity
         {
-            if (!change_trackers.ContainsKey(typeof(T)))
-            {
-                var tracker = factory.create_for<T>();
-                this.log().debug("tracker: {0}", tracker);
-                change_trackers.Add(typeof(T), tracker);
-            }
+            if (!change_trackers.ContainsKey(typeof (T))) change_trackers.Add(typeof (T), factory.create_for<T>());
             return change_trackers[typeof (T)].downcast_to<IChangeTracker<T>>();
         }
     }
trunk/product/MyMoney/Infrastructure/transactions2/TransactionSpecs.cs
@@ -77,14 +77,12 @@ namespace MoMoney.Infrastructure.transactions2
                     entity = an<IEntity>();
                     update_statement = an<IStatement>();
 
-                    Log.For(entity).debug("context");
                     when_the(registry).is_told_to(x => x.prepare_update_statement_for(entity)).it_will_return( update_statement).Repeat.Any();
                 };
 
         because b =
             () =>
                 {
-                    Log.For(entity).debug("because");
                     sut.add_dirty(entity);
                     sut.commit_changes();
                 };
trunk/product/MyMoney/MyMoney.csproj
@@ -211,6 +211,11 @@
     <Compile Include="Domain\Core\range_specs.cs" />
     <Compile Include="Domain\repositories\IBillRepository.cs" />
     <Compile Include="Domain\repositories\ICompanyRepository.cs" />
+    <Compile Include="Infrastructure\transactions2\ChangeTracker.cs" />
+    <Compile Include="Infrastructure\transactions2\ChangeTrackerFactory.cs" />
+    <Compile Include="Infrastructure\transactions2\ChangeTrackerFactorySpecs.cs" />
+    <Compile Include="Infrastructure\transactions2\ChangeTrackerSpecs.cs" />
+    <Compile Include="Infrastructure\transactions2\Database.cs" />
     <Compile Include="Infrastructure\transactions2\IChangeTracker.cs" />
     <Compile Include="Infrastructure\transactions2\IChangeTrackerFactory.cs" />
     <Compile Include="Infrastructure\transactions2\IdentityMapProxy.cs" />
@@ -302,8 +307,13 @@
     <Compile Include="Infrastructure\transactions2\IDatabase.cs" />
     <Compile Include="Infrastructure\transactions2\IStatement.cs" />
     <Compile Include="Infrastructure\transactions2\IStatementRegistry.cs" />
+    <Compile Include="Infrastructure\transactions2\ITrackerEntry.cs" />
+    <Compile Include="Infrastructure\transactions2\ITrackerEntryMapper.cs" />
     <Compile Include="Infrastructure\transactions2\Session.cs" />
+    <Compile Include="Infrastructure\transactions2\SessionFactory.cs" />
+    <Compile Include="Infrastructure\transactions2\SessionFactorySpecs.cs" />
     <Compile Include="Infrastructure\transactions2\SessionSpecs.cs" />
+    <Compile Include="Infrastructure\transactions2\StatementRegistry.cs" />
     <Compile Include="Infrastructure\transactions2\Transaction.cs" />
     <Compile Include="Infrastructure\transactions2\TransactionSpecs.cs" />
     <Compile Include="Infrastructure\transactions\IUnitOfWorkRegistrationFactory.cs" />