Commits

sake  committed 4f2c66b

refactor Reconciler out, introduce IMetaInfo, MetaInfoBuilder

  • Participants
  • Parent commits 5d31866

Comments (0)

Files changed (1)

File Usually/Resolve.cs

     {
         public string _expression = null;
         public int _id = -1;
-        public GeneratingValue(string expr, int id) 
+        public GeneratingValue(string expr, int id)
         { 
             this._expression = expr;
             this._id = id;
         void Value(string name, Func<T, object> getValue);
         IKeyBuilder<T> ExtraKey(string group);
     }
-    public interface IRelationBuilder<Master, Detail>
+    public interface IMetaInfo<T>
     {
-        void Link(Func<Master, object> masterKey, Func<Detail, object> detalKey);
+        string TableName { get; }
+        object[] GetKey(T obj);
+        void ForEachKey(T obj, Action<string, object> action);
+        void ForEachExtraKey(string group, T obj, Action<string, object> action);
+        void ForEachInsertValue(Func<string, object> newgen, T obj, Action<string, object> action);
+        void ForEachValueChange(T o, T n, Action<string, object, object> action);
     }
-    public delegate void RelMeta<Master, Detail>(IRelationBuilder<Master, Detail> r);
+
     public static class MetaBuilderExtension
     {
         public static void Key<T>(this IKeyBuilder<T> m, string name, Func<T, object> getKey, string sequence, Func<object, bool> isDummy)
             m.StringKey(name, getKey, sequence, (s) => s.StartsWith(prefix));
         }
     }
-    public class Reconciler<T> : IMetaBuilder<T>
+    public class MetaInfoBuilder<T> : IMetaBuilder<T>, IMetaInfo<T>
     {
-        class ColumnsDef
+        #region Nested Classes
+        private class ColumnsDef
         {
             private List<string> names = new List<string>();
             private Dictionary<string, Func<T, object>> getters = new Dictionary<string, Func<T, object>>();
                 return values;
             }
         }
-        class KeysDef: ColumnsDef, IKeyBuilder<T>
+        private class KeysDef: ColumnsDef, IKeyBuilder<T>
         {
             private Dictionary<string, Func<object, string>> generators = new Dictionary<string, Func<object, string>>();
             public void Add(string name, Func<T, object> getKey, Func<object, string> generator = null)
                 return g(value);
             }
         }
-        class ValuesDef : ColumnsDef
+        private class ValuesDef : ColumnsDef
         {
             public new void Add(string name, Func<T, object> getValue)
             {
                 base.Add(name, getValue);
             }
         }
-        private int nextGenId = 1;
+        #endregion
+
+        #region Private Fields
         private string tableName;
         private KeysDef keys = new KeysDef();
+        private Dictionary<string, KeysDef> extraKeys = new Dictionary<string, KeysDef>();
         private ValuesDef values = new ValuesDef();
-        private Dictionary<string, KeysDef> extraKeys = new Dictionary<string, KeysDef>();
-        public void Table(string name) { this.tableName = name; }
-        public void Key(string name, Func<T, object> getKey, Func<object, string> generator = null)
+        #endregion
+
+        #region Implement IMetaBuilder<T>
+        void IMetaBuilder<T>.Table(string name) { this.tableName = name; }
+        void IKeyBuilder<T>.Key(string name, Func<T, object> getKey, Func<object, string> generator)
         {
             this.keys.Add(name, getKey, generator);
         }
-        public IKeyBuilder<T> ExtraKey(string group)
+        IKeyBuilder<T> IMetaBuilder<T>.ExtraKey(string group)
         {
             KeysDef r = null;
             if (this.extraKeys.TryGetValue(group, out r)) return r;
             this.extraKeys.Add(group, r);
             return r;
         }
-        public void Value(string name, Func<T, object> getValue)
+        void IMetaBuilder<T>.Value(string name, Func<T, object> getValue)
         {
             this.values.Add(name, getValue);
         }
-        public object[] GetKey(T obj)
+        #endregion
+
+        #region Implement IMetaInfo<T>
+        string IMetaInfo<T>.TableName { get { return this.tableName; } }
+        object[] IMetaInfo<T>.GetKey(T obj)
         {
             return this.keys.GetFrom(obj);
         }
-        private GeneratingValue NewGeneratingValue(string expr)
+        void IMetaInfo<T>.ForEachKey(T obj, Action<string, object> action)
         {
-            var r = new GeneratingValue(expr, this.nextGenId);
-            this.nextGenId++;
-            return r;
+            this.keys.ForEach(obj, action);
         }
-        public void ForEachInsertValue(T obj, Action<string, object> action)
+        void IMetaInfo<T>.ForEachExtraKey(string group, T obj, Action<string, object> action)
+        {
+            this.extraKeys[group].ForEach(obj, action);
+        }
+        void IMetaInfo<T>.ForEachInsertValue(Func<string, object> newgen, T obj, Action<string, object> action)
         {
             var done = new HashSet<string>();
             Action<KeysDef, string, object> addKey = (keys, k, v) =>
                 if (!done.Contains(k))
                 {
                     var expr = keys.GeneratingExpr(k, v);
-                    action(k, string.IsNullOrEmpty(expr) ? v : this.NewGeneratingValue(expr));
+                    action(k, string.IsNullOrEmpty(expr) ? v : newgen(expr));
                     done.Add(k);
                 }
             };
                 if (!done.Contains(k)) action(k, v);
             });
         }
-        public void BuildLookups(IEnumerable<T> olds, IEnumerable<T> news, ref Dictionary<object[], T> oldLookup, ref Dictionary<object[], T> newLookup)
+        void IMetaInfo<T>.ForEachValueChange(T o, T n, Action<string, object, object> action)
         {
-            if (oldLookup == null)
+            this.values.ForEachChange(o, n, action);
+        }
+        public Reconciler<T> CreateReconciler(IEnumerable<T> olds, IEnumerable<T> news)
+        {
+            return new Reconciler<T>(this, olds, news);
+        }
+        #endregion
+    }
+    public delegate void Meta<T>(IMetaBuilder<T> m);
+    public class Reconciler<T>
+    {
+        public struct Insertion
+        {
+            public InsertRecord Record;
+            public T Object;
+        }
+        private int nextGenId = 1;
+        private IMetaInfo<T> info = null;
+        private IEnumerable<T> olds = null;
+        private IEnumerable<T> news = null;
+        private Dictionary<object[], T> oldLookup = null;
+        private Dictionary<object[], T> newLookup = null;
+        public Reconciler(IMetaInfo<T> info, IEnumerable<T> olds, IEnumerable<T> news)
+        {
+            this.info = @info;
+            this.olds = @olds;
+            this.news = @news;
+            this.oldLookup = CreateLookup(this.info, olds);
+            this.newLookup = CreateLookup(this.info, news);
+        }
+        private static Dictionary<object[], T> CreateLookup(IMetaInfo<T> info, IEnumerable<T> list)
+        {
+            var r = new Dictionary<object[], T>(JonSkeet.ArrayEqualityComparer<object>.Default);
+            foreach (var o in list) r.Add(info.GetKey(o), o);
+            if (r.Count != list.Count()) throw new Exception("Duplicate keys");
+            return r;
+        }
+        private GeneratingValue NewGeneratingValue(string expr)
+        {
+            var r = new GeneratingValue(expr, this.nextGenId);
+            this.nextGenId++;
+            return r;
+        }
+        public IEnumerable<Insertion> ReconcileInsertion()
+        {
+            foreach (var n in this.news)
             {
-                oldLookup = new Dictionary<object[], T>(JonSkeet.ArrayEqualityComparer<object>.Default);
-                foreach (var o in olds) oldLookup.Add(this.GetKey(o), o);
-                if (oldLookup.Count != olds.Count()) throw new Exception("Duplicate keys");
-            }
-            if (newLookup == null)
-            {
-                newLookup = new Dictionary<object[], T>(JonSkeet.ArrayEqualityComparer<object>.Default);
-                foreach (var n in news) newLookup.Add(this.GetKey(n), n);
-                if (newLookup.Count != news.Count()) throw new Exception("Duplicate keys");
-            }
-        }
-        public IEnumerable<TransactionRecord> ReconcileInsert(IEnumerable<T> olds, IEnumerable<T> news, Dictionary<object[], T> oldLookup, Dictionary<object[], T> newLookup)
-        {
-            this.BuildLookups(olds, news, ref oldLookup, ref newLookup);
-            foreach (var n in news)
-            {
-                var key = this.GetKey(n);
+                var key = this.info.GetKey(n);
                 T o = default(T);
-                if (!oldLookup.TryGetValue(key, out o))
+                if (!this.oldLookup.TryGetValue(key, out o))
                 {
-                    var r = new InsertRecord(this.tableName);
-                    this.ForEachInsertValue(n, (k, v) => r.Values[k] = v);
-                    if (r.Values.Any()) yield return r;
+                    var r = new InsertRecord(this.info.TableName);
+                    this.info.ForEachInsertValue(this.NewGeneratingValue, n, (k, v) => r.Values[k] = v);
+                    if (r.Values.Any()) yield return new Insertion { Record = r, Object = n };
                 }
             }
         }
-        public IEnumerable<TransactionRecord> ReconcileUpdateAndDelete(IEnumerable<T> olds, IEnumerable<T> news, Dictionary<object[], T> oldLookup, Dictionary<object[], T> newLookup)
+        public IEnumerable<TransactionRecord> ReconcileInsert()
         {
-            this.BuildLookups(olds, news, ref oldLookup, ref newLookup);
-            foreach (var o in olds)
+            return from i in this.ReconcileInsertion() select i.Record;
+        }
+        public IEnumerable<TransactionRecord> ReconcileUpdateAndDelete()
+        {
+            foreach (var o in this.olds)
             {
-                var key = this.GetKey(o);
+                var key = this.info.GetKey(o);
                 T n = default(T);
                 if (newLookup.TryGetValue(key, out n))
                 {
-                    var r = new UpdateRecord(this.tableName);
+                    var r = new UpdateRecord(this.info.TableName);
                     r.AtMostOne = true;
-                    this.keys.ForEach(n, (k, v) => r.Keys[k] = v);
-                    this.values.ForEachChange(o, n, (k, ov, nv) => r.Values[k] = nv);
+                    this.info.ForEachKey(n, (k, v) => r.Keys[k] = v);
+                    this.info.ForEachValueChange(o, n, (k, ov, nv) => r.Values[k] = nv);
                     if (r.Keys.Any() && r.Values.Any()) yield return r;
                 }
                 else
                 {
-                    var r = new DeleteRecord(this.tableName);
+                    var r = new DeleteRecord(this.info.TableName);
                     r.AtMostOne = true;
-                    this.keys.ForEach(o, (k, v) => r.Keys[k] = v);
+                    this.info.ForEachKey(o, (k, v) => r.Keys[k] = v);
                     if (r.Keys.Any()) yield return r;
                 }
             }
         }
-
-        public IEnumerable<TransactionRecord> Reconcile(IEnumerable<T> olds, IEnumerable<T> news)
+        public IEnumerable<TransactionRecord> Reconcile()
         {
-            Dictionary<object[], T> oldLookup = null;
-            Dictionary<object[], T> newLookup = null;
-            this.BuildLookups(olds, news, ref oldLookup, ref newLookup);
-            foreach (var t in this.ReconcileInsert(olds, news, oldLookup, newLookup)) yield return t;
-            foreach (var t in this.ReconcileUpdateAndDelete(olds, news, oldLookup, newLookup)) yield return t;
+            return this.ReconcileInsert().Union(this.ReconcileUpdateAndDelete());
         }
     }
-    public delegate void Meta<T>(IMetaBuilder<T> m);
     public class Resolver
     {
         public const int DEFAULT_DUMMY_START = -1;
         }
         public IEnumerable<TransactionRecord> Resolve()
         {
-            foreach (var i in this.items)
-                foreach (var r in i.Resolve())
-                    yield return r;
+            return null;
         }
         public static IEnumerable<TransactionRecord> Reconcile<T>(Meta<T> meta, IEnumerable<T> olds, IEnumerable<T> news)
         {
-            var r = new Reconciler<T>();
-            meta(r);
-            return r.Reconcile(olds, news);
+            var m = new MetaInfoBuilder<T>();
+            meta(m);
+            return m.CreateReconciler(olds, news).Reconcile();
         }
     }
     public interface IResolverItem
     {
-        IEnumerable<TransactionRecord> Resolve();
+        string Group { get; }
     }
     public class ResolverItem<T> : IResolverItem
     {
         private List<IResolverItem> items = new List<IResolverItem>();
-        private Meta<T> meta = null;
+        private IMetaInfo<T> info = null;
         private string group = null;
         private Func<T, object> getRef = null;
         private IEnumerable<T> olds = null;
         private IEnumerable<T> news = null;
+        string IResolverItem.Group { get { return this.group; } }
         public ResolverItem(Meta<T> meta, string group, Func<T, object> getRef, IEnumerable<T> olds, IEnumerable<T> news)
         {
-            this.meta = @meta;
+            var m = new MetaInfoBuilder<T>();
+            meta(m);
+            this.info = m;
             this.group = @group;
             this.getRef = @getRef;
             this.olds = @olds;
         }
         public IEnumerable<TransactionRecord> Resolve()
         {
-            return null;
+            var r = new Reconciler<T>(this.info, this.olds, this.news);
+            foreach (var ins in r.ReconcileInsertion())
+            {
+                foreach (var item in this.items)
+                {
+                    if (String.IsNullOrEmpty(item.Group))
+                    {
+                    }
+                    else
+                    {
+                    }
+                }
+            }
+            return r.ReconcileInsert().Union(r.ReconcileUpdateAndDelete());
         }
     }
 }