Commits

Anonymous committed ec5fbf7

complete without test Settler

Comments (0)

Files changed (1)

Usually/Resolve.cs

         string GeneratorExpr(string name, object value);
         void ForEachKey(T obj, Action<string, object> action);
         void ForEachExtraKey(string group, T obj, Action<string, object> action);
+        void ForEachValue(T obj, Action<string, object> action);
         void ForEachInsertValue(T obj, Action<string, object> action);
         void ForEachValueChange(T o, T n, Action<string, object, object> action);
         string MasterKeyGroup { get; }
             this.getters.Add(name, getter);
             this.names.Add(name);
         }
+        public int Count
+        {
+            get { return this.names.Count; }
+        }
         public bool ContainsKey(string name)
         {
             return this.getters.ContainsKey(name);
         {
             this.extraKeys[group].ForEach(obj, action);
         }
+        void IMetaInfo<T>.ForEachValue(T obj, Action<string, object> action)
+        {
+            this.values.ForEach(obj, action);
+        }
         void IMetaInfo<T>.ForEachValueChange(T o, T n, Action<string, object, object> action)
         {
             this.values.ForEachChange(o, n, action);
         }
     }
     public delegate void Meta<T>(IMetaBuilder<T> m);
-    abstract class AbstractReconciler<OldT, NewT>
+    public abstract class AbstractReconciler<OldT, NewT>
     {
         protected abstract IMetaInfo<OldT> GetOldInfo();
         protected abstract IMetaInfo<NewT> GetNewInfo();
             this.info.ForEachValueChange(o, n, action);
         }
     }
+    public class BaseResolverItem
+    {
+    }
     public class Resolver
     {
         public const int DEFAULT_DUMMY_START = -1;
         private Resolver host = null;
         private IList<IResolverItem> items = new List<IResolverItem>();
         private IMetaInfo<T> info = null;
-        private string group = null;
         private IEnumerable<T> olds = null;
         private IEnumerable<T> news = null;
         private IDictionary<object[], IList<TransactionJournal<T, T>>> _journals = null;
             if (!this._journals.TryGetValue(masterKey, out r)) return Enumerable.Empty<TransactionJournal<T, T>>();
             return r;
         }
-        string IResolverItem.Group { get { return this.group; } }
+        string IResolverItem.Group { get { return this.info.MasterKeyGroup; } }
         public ResolverItem(Resolver host, Meta<T> meta, IEnumerable<T> olds, IEnumerable<T> news)
         {
             this.host = @host;
     }
     public class GenericItemList<T> where T : class
     {
-        class GenericItemMetaInfo : IMetaInfo<object[]>
+        public class GenericItemMetaInfo : IMetaInfo<object[]>
         {
             private IMetaInfo<T> specific = null;
             private Dictionary<string, int> indices = null;
             private Dictionary<string, string[]> extraKeys = null;
             private string[] values = null;
             private string[] refs = null;
-            public GenericItemMetaInfo(Meta<T> meta)
+            public IMetaInfo<T> Specific { get { return this.specific; } }
+            public GenericItemMetaInfo(IMetaInfo<T> info)
             {
-                var @inner = new MetaInfoBuilder<T>();
-                var @info = @inner as IMetaInfo<T>;
-                meta(@inner);
                 var @indices = new Dictionary<string, int>();
                 var @keys = new List<string>();
                 var @extraKeys = new Dictionary<string, string[]>();
                     });
                     @extraKeys.Add(g, @xkeys.ToArray());
                 }
-                @info.ForEachInsertValue(null, (k, v) =>
+                @info.ForEachValue(null, (k, v) =>
                 {
-                    if (!@indices.ContainsKey(k))
-                    {
-                        @indices.Add(k, i++);
-                        @values.Add(k);
-                    }
+                    @indices.Add(k, i++);
+                    @values.Add(k);
                 });
                 var @refs = @info.GetRefList().ToArray();
-                this.specific = @inner;
+                this.specific = @info;
                 this.indices = @indices;
                 this.keys = @keys.ToArray();
                 this.extraKeys = @extraKeys;
                     foreach (var k in xkeys) action(k, obj[i++]);
                 }
             }
+            void IMetaInfo<object[]>.ForEachValue(object[] obj, Action<string, object> action)
+            {
+                foreach (var k in this.values)
+                {
+                    action(k, obj[this.indices[k]]);
+                }
+            }
             void IMetaInfo<object[]>.ForEachInsertValue(object[] obj, Action<string, object> action)
             {
                 this.specific.ForEachInsertValue(null, (k, v) =>
             }
             string IMetaInfo<object[]>.MasterKeyGroup
             {
-                get
-                {
-                    return this.specific.MasterKeyGroup;
-                }
+                get { return this.specific.MasterKeyGroup; }
             }
             object[] IMetaInfo<object[]>.GetMasterRef(object[] obj)
             {
             {
                 return this.specific.GetExtraKeyGroups();
             }
-
             IEnumerable<string> IMetaInfo<object[]>.GetRefList()
             {
                 return this.specific.GetRefList();
             }
         }
-        class GenericItemReconciler: AbstractReconciler<object[], T>
+        public class GenericItemReconciler : AbstractReconciler<object[], T>
         {
+            private IMetaInfo<object[]> oldInfo;
+            private IMetaInfo<T> newInfo;
+            private IEnumerable<object[]> olds;
+            private IEnumerable<T> news;
+            private IDictionary<object[], object[]> oldLookup = null;
+            private IDictionary<object[], T> newLookup = null;
+            public GenericItemReconciler(IMetaInfo<object[]> oldInfo, IMetaInfo<T> newInfo, IEnumerable<object[]> olds, IEnumerable<T> news)
+            {
+                this.oldInfo = oldInfo;
+                this.newInfo = newInfo;
+                this.olds = olds;
+                this.news = news;
+                this.oldLookup = CreateLookup(this.GetOldInfo(), @olds);
+                this.newLookup = CreateLookup(this.GetNewInfo(), @news);
+            }
             protected override IMetaInfo<object[]> GetOldInfo()
             {
-                throw new NotImplementedException();
+                return this.oldInfo;
             }
             protected override IMetaInfo<T> GetNewInfo()
             {
-                throw new NotImplementedException();
+                return this.newInfo;
             }
             protected override IDictionary<object[], object[]> GetOldLookup()
             {
-                throw new NotImplementedException();
+                return this.oldLookup;
             }
             protected override IDictionary<object[], T> GetNewLookup()
             {
-                throw new NotImplementedException();
+                return this.newLookup;
             }
             protected override IEnumerable<object[]> GetOlds()
             {
-                throw new NotImplementedException();
+                return this.olds;
             }
             protected override IEnumerable<T> GetNews()
             {
-                throw new NotImplementedException();
-            }
-            protected override TransactionJournal<object[], T> CreateJournal(object[] o, T n)
-            {
-                throw new NotImplementedException();
+                return this.news;
             }
             protected override void ForEachValueChange(object[] o, T n, Action<string, object, object> action)
             {
-                throw new NotImplementedException();
+                var oldInfo = this.GetOldInfo();
+                var newInfo = this.GetNewInfo();
+                var oldValues = new Dictionary<string, object>();
+                oldInfo.ForEachValue(o, oldValues.Add);
+                newInfo.ForEachValue(n, (k, nv) =>
+                {
+                    var ov = oldValues[k];
+                    if (!EqualityComparer<object>.Default.Equals(ov, nv))
+                        action(k, ov, nv);
+                });
             }
         }
-        private List<object[]> items = new List<object[]>(); 
+        private List<object[]> items = new List<object[]>();
         private GenericItemMetaInfo info = null;
-        public GenericItemList(Meta<T> meta)
+        private IEnumerable<T> source = null;
+        public GenericItemList(IMetaInfo<T> info)
         {
-            this.info = new GenericItemMetaInfo(meta);
+            this.info = new GenericItemMetaInfo(info);
+        }
+        public string TableName
+        {
+            get { return (this.info as IMetaInfo<object[]>).TableName; }
+        }
+        public IMetaInfo<object[]> Info
+        {
+            get { return this.info; }
         }
         public object[] Add(T obj)
         {
             this.items.Add(item);
             return item;
         }
+        public void Load(IEnumerable<T> source)
+        {
+            this.Clear();
+            foreach (var i in @source) this.Add(i as T);
+            this.source = @source;
+        }
+        public void Load(Func<string, IEnumerable<object>> data)
+        {
+            this.Load(data(this.info.Specific.TableName).Cast<T>());
+        }
         public void Clear()
         {
             this.items.Clear();
+            this.source = null;
         }
         public int Count 
         { 
             get { return this.items.Count; } 
         }
+        public AbstractReconciler<object[], T> newReconciler()
+        {
+            return new GenericItemReconciler(this.info, this.info.Specific, this.items, this.source);
+        }
     }
-    public class Settler<T> where T : class
+    public class Settler
     {
-        public class SettlerItem
+        private Func<string, object> generator = null;
+        private IList<ISettlerItem> items = new List<ISettlerItem>();
+        private IList<ISettlerItem> roots = new List<ISettlerItem>();
+        public interface ISettlerItem
         {
-            public SettlerItem Add(string name, Meta<T> meta)
+            string TableName { get; }
+            string Group { get; }
+            void Load(Func<string, IEnumerable<object>> data);
+            IEnumerable<TransactionRecord> ResolveForRoot();
+            IEnumerable<TransactionRecord> ResolveForMasterInsert(object[] refKey, object[] actualKey);
+            IEnumerable<TransactionRecord> ResolveForMasterStatic(object[] refKey);
+            IEnumerable<TransactionRecord> ResolveForMasterDelete(object[] refKey);
+        }
+        public class SettlerItem<T>: ISettlerItem where T : class
+        {
+            private Settler host;
+            private List<ISettlerItem> items = new List<ISettlerItem>();
+            private IMetaInfo<T> info = null;
+            private GenericItemList<T> list = null;
+            private IDictionary<object[], IList<TransactionJournal<object[], T>>> _journals = null;
+            protected IDictionary<object[], IList<TransactionJournal<object[], T>>> CreateJournals()
             {
-                return null;
+                var r = new Dictionary<object[], IList<TransactionJournal<object[], T>>>(JonSkeet.ArrayEqualityComparer<object>.Default);
+                var reconciler = this.list.newReconciler();
+                foreach (var j in reconciler.ReconcileNonDelete())
+                {
+                    var k = this.info.GetMasterRef(j.New);
+                    IList<TransactionJournal<object[], T>> list = null;
+                    if (!r.TryGetValue(k, out list))
+                    {
+                        list = new List<TransactionJournal<object[], T>>();
+                        r.Add(k, list);
+                    }
+                    list.Add(j);
+                }
+                foreach (var j in reconciler.ReconcileDelete())
+                {
+                    var k = this.list.Info.GetMasterRef(j.Old);
+                    IList<TransactionJournal<object[], T>> list = null;
+                    if (!r.TryGetValue(k, out list))
+                    {
+                        list = new List<TransactionJournal<object[], T>>();
+                        r.Add(k, list);
+                    }
+                    list.Add(j);
+                }
+                return r;
+            }
+            public SettlerItem(Settler settler, Meta<T> meta)
+            {
+                this.host = settler;
+                var builder = new MetaInfoBuilder<T>();
+                meta(builder);
+                this.info = builder;
+                this.list = new GenericItemList<T>(this.info);
+            }
+            string ISettlerItem.TableName
+            {
+                get { return this.info.TableName; }
+            }
+            string ISettlerItem.Group
+            {
+                get { return this.info.MasterKeyGroup; }
+            }
+            public ISettlerItem Add(string name, Meta<T> meta)
+            {
+                this.host.CheckBeforeAdd(name);
+                var r = new SettlerItem<T>(this.host, meta);
+                this.items.Add(r);
+                return r;
+            }
+            void ISettlerItem.Load(Func<string, IEnumerable<object>> data)
+            {
+                this.list.Load(data);
+                foreach (var i in this.items) i.Load(data);
+            }
+            protected IEnumerable<TransactionJournal<object[], T>> GetJournals(object[] masterKey)
+            {
+                if (this._journals == null) this._journals = this.CreateJournals();
+                IList<TransactionJournal<object[], T>> r = null;
+                if (!this._journals.TryGetValue(masterKey, out r)) return Enumerable.Empty<TransactionJournal<object[], T>>();
+                return r;
+            }
+            private void GenerateKey(InsertRecord ins)
+            {
+                foreach (var i in ins.Values.ToArray())
+                {
+                    var expr = this.list.Info.GeneratorExpr(i.Key, i.Value);
+                    if (expr != null)
+                    {
+                        var g = this.host.Generate(expr);
+                        if (g != null) ins.Values[i.Key] = g;
+                    }
+                }
+            }
+            private object[] GetKeyForDetail(ISettlerItem i, T obj)
+            {
+                return String.IsNullOrEmpty(i.Group)
+                     ? this.info.GetKey(obj)
+                     : this.info.GetExtraKey(i.Group, obj);
+            }
+            private object[] GetKeyForDetail(ISettlerItem i, object[] obj)
+            {
+                return String.IsNullOrEmpty(i.Group)
+                     ? this.list.Info.GetKey(obj)
+                     : this.list.Info.GetExtraKey(i.Group, obj);
+            }
+            private object[] GetKeyForDetail(ISettlerItem i, IDictionary<string, object> dict)
+            {
+                return String.IsNullOrEmpty(i.Group)
+                     ? this.info.GetKey(dict)
+                     : this.info.GetExtraKey(i.Group, dict);
+            }
+            protected void SetActualMasterKey(TransactionRecord t, object[] actualKey)
+            {
+                IDictionary<string, object> dict = null;
+                if (t is InsertRecord) dict = (t as InsertRecord).Values;
+                if (t is UpdateRecord) dict = (t as InsertRecord).Values;
+                if (dict == null) throw new Exception("Unexpect type: " + t.GetType().Name);
+                this.info.SetActualMasterKey(dict, actualKey);
+            }
+            IEnumerable<TransactionRecord> ISettlerItem.ResolveForMasterInsert(object[] refKey, object[] actualKey)
+            {
+                foreach (var j in this.GetJournals(refKey))
+                {
+                    var records = (j.Record is InsertRecord)
+                                ? this.ResolveForInsert(j)
+                                : this.ResolveForStatic(j);
+                    foreach (var t in records)
+                    {
+                        if (t == j.Record) this.SetActualMasterKey(t, actualKey);
+                        yield return t;
+                    }
+                }
+            }
+            IEnumerable<TransactionRecord> ISettlerItem.ResolveForMasterStatic(object[] refKey)
+            {
+                foreach (var j in this.GetJournals(refKey))
+                {
+                    var records = Enumerable.Empty<TransactionRecord>();
+                    if (j.Record is InsertRecord)
+                        records = this.ResolveForInsert(j);
+                    else if ((j.Record == null) || (j.Record is UpdateRecord))
+                        records = this.ResolveForStatic(j);
+                    else if (j.Record is DeleteRecord) records =
+                        records = this.ResolveForDelete(j);
+                    foreach (var t in records) yield return t;
+                }
+            }
+            IEnumerable<TransactionRecord> ISettlerItem.ResolveForMasterDelete(object[] refKey)
+            {
+                foreach (var j in this.GetJournals(refKey))
+                {
+                    var records = Enumerable.Empty<TransactionRecord>();
+                    if (j.Record is DeleteRecord) records = this.ResolveForDelete(j);
+                    else if ((j.Record == null) || (j.Record is UpdateRecord))
+                    {
+                        var del = new DeleteRecord(this.info.TableName);
+                        this.list.Info.ForEachKey(j.Old, del.Keys.Add);
+                        var jdel = new TransactionJournal<object[], T> { Record = del, Old = j.Old, New = default(T) };
+                        records = this.ResolveForDelete(jdel);
+                    }
+                    foreach (var t in records) yield return t;
+                }
+            }
+            protected IEnumerable<TransactionRecord> ResolveForInsert(TransactionJournal<object[], T> j)
+            {
+                var ins = (InsertRecord)j.Record;
+                this.GenerateKey(ins);
+                yield return ins;
+                foreach (var i in this.items)
+                {
+                    var refKey = this.GetKeyForDetail(i, j.New);
+                    var actualKey = this.GetKeyForDetail(i, ins.Values);
+                    foreach (var t in i.ResolveForMasterInsert(refKey, actualKey))
+                        yield return t;
+                }
+            }
+            protected IEnumerable<TransactionRecord> ResolveForStatic(TransactionJournal<object[], T> j)
+            {
+                if (j.Record != null) yield return j.Record;
+                foreach (var i in this.items)
+                {
+                    var refKey = this.GetKeyForDetail(i, j.New);
+                    foreach (var t in i.ResolveForMasterStatic(refKey))
+                        yield return t;
+                }
+            }
+            protected IEnumerable<TransactionRecord> ResolveForDelete(TransactionJournal<object[], T> j)
+            {
+                foreach (var i in this.items)
+                {
+                    var refKey = this.GetKeyForDetail(i, j.Old);
+                    foreach (var t in i.ResolveForMasterDelete(refKey))
+                        yield return t;
+                }
+                yield return j.Record;
+            }
+            IEnumerable<TransactionRecord> ISettlerItem.ResolveForRoot()
+            {
+                var r = this.list.newReconciler();
+                foreach (var j in r.ReconcileNonDelete())
+                {
+                    if (j.Record is InsertRecord)
+                        foreach (var t in this.ResolveForInsert(j))
+                            yield return t;
+                    else
+                        foreach (var t in this.ResolveForStatic(j))
+                            yield return t;
+                }
+                foreach (var j in r.ReconcileDelete())
+                {
+                    foreach (var t in this.ResolveForDelete(j))
+                        yield return t;
+                }
             }
         }
-        public SettlerItem Add(string name, Meta<T> meta)
+        public Settler(Func<string, object> generator)
         {
-            return null;
+            this.generator = generator;
         }
-        public void Load(Func<string, IEnumerable<T>> data)
+        void CheckBeforeAdd(string name)
         {
+            if (this.items.Any(i => (i.TableName == name))) throw new Exception("Duplicate item: " + name);
+        }
+        public SettlerItem<T> Add<T>(string name, Meta<T> meta) where T: class
+        {
+            this.CheckBeforeAdd(name);
+            var r = new SettlerItem<T>(this, meta);
+            this.roots.Add(r);
+            return r;
+        }
+        public void Load(Func<string, IEnumerable<object>> data)
+        {
+            foreach (var r in this.roots) r.Load(data);
+        }
+        public object Generate(string expr)
+        {
+            return (this.generator == null) ? null : this.generator(expr);
         }
         public IEnumerable<TransactionRecord> Resolve()
         {
-            return null;
+            return this.items.SelectMany((i) => i.ResolveForRoot());
         }
     }
 }