Commits

sake  committed 2819a07

huge refactor

  • Participants
  • Parent commits 300dac1

Comments (0)

Files changed (2)

File Usually/Resolve.cs

 
 namespace Usually
 {
-    public interface ITransactor
-    {
-        void Insert(InsertRecord ins);
-        void Update(UpdateRecord upd);
-        void Delete(DeleteRecord del);
-    }
     public abstract class TransactionRecord
     {
         public string TableName = null;
         protected TransactionRecord() : this(null) { }
         protected TransactionRecord(string tableName) { this.TableName = @tableName; }
         public abstract TransactionRecord CloneRecord();
-        public abstract void Execute(ITransactor actor);
     }
     public sealed class InsertRecord : TransactionRecord
     {
         {
             return this.CloneInsert();
         }
-        public override void Execute(ITransactor actor)
-        {
-            actor.Insert(this);
-        }
     }
     public sealed class UpdateRecord : TransactionRecord
     {
         {
             return this.CloneUpdate();
         }
-        public override void Execute(ITransactor actor)
-        {
-            actor.Update(this);
-        }
     }
     public sealed class DeleteRecord : TransactionRecord
     {
         {
             return this.CloneDelete();
         }
-        public override void Execute(ITransactor actor)
-        {
-            actor.Delete(this);
-        }
     }
     public class TransactionJournal<OldT, NewT>
     {
         void MasterExtaKey(string group);
         void Ref(string name, Func<T, object> getRef);
         void Value(string name, Func<T, object> getValue);
-        IKeyBuilder<T> ExtraKey(string group);
+        void ExtraKey(string group, string name, Func<T, object> getKey, Func<object, string> generator = null);
     }
     public interface IMetaInfo<T>
     {
         string MasterKeyGroup { get; }
         object[] GetMasterRef(T obj);
         void SetActualMasterKey(IDictionary<string, object> dict, object[] actualKey);
+        IEnumerable<string> GetExtraKeyGroups();
+        IEnumerable<string> GetRefList();
     }
-    public static class MetaBuilderExtension
+    public static class IKeyBuilderExtension
     {
         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 static class IMetaBuilderExtension
+    {
+        public static void ExtraKey<T>(this IMetaBuilder<T> m, string group, string name, Func<T, object> getKey, string sequence, Func<object, bool> isDummy)
+        {
+            m.ExtraKey(group, name, getKey, (x) => (isDummy(x) ? sequence : null));
+        }
+        public static void ExtraIntegerKey<T>(this IMetaBuilder<T> m, string group, string name, Func<T, int?> getKey, string sequence, Func<int, bool> isDummy)
+        {
+            m.ExtraKey(group, name, (x) => getKey(x), sequence, (x) => isDummy((int)x));
+        }
+        public static void ExtraIntegerKey<T>(this IMetaBuilder<T> m, string group, string name, Func<T, int?> getKey, string sequence, int dummy = Resolver.DEFAULT_DUMMY_START)
+        {
+            m.ExtraIntegerKey(group, name, getKey, sequence, (x) => x <= dummy);
+        }
+        public static void ExtraDecimalKey<T>(this IMetaBuilder<T> m, string group, string name, Func<T, decimal?> getKey, string sequence, Func<decimal, bool> isDummy)
+        {
+            m.ExtraKey(group, name, (x) => getKey(x), sequence, (x) => isDummy((decimal)x));
+        }
+        public static void ExtraDecimalKey<T>(this IMetaBuilder<T> m, string group, string name, Func<T, decimal?> getKey, string sequence, decimal dummy = Resolver.DEFAULT_DUMMY_START)
+        {
+            m.ExtraDecimalKey(group, name, getKey, sequence, (x) => x <= dummy);
+        }
+        public static void ExtraStringKey<T>(this IMetaBuilder<T> m, string group, string name, Func<T, object> getKey, string sequence, Func<string, bool> isDummy)
+        {
+            m.ExtraKey(group, name, getKey, sequence, (x) => isDummy(x as string));
+        }
+        public static void ExtraStringKey<T>(this IMetaBuilder<T> m, string group, string name, Func<T, object> getKey, string sequence, string prefix = "new:")
+        {
+            m.ExtraStringKey(group, name, getKey, sequence, (s) => s.StartsWith(prefix));
+        }
+    }
     class ColumnsDef<T>
     {
         private IList<string> names = new List<string>();
             this.getters.Add(name, getter);
             this.names.Add(name);
         }
-        public int Count { get { return this.names.Count; } }
-        public IEnumerable<string> Names { get { return this.names; } }
+        public bool ContainsKey(string name)
+        {
+            return this.getters.ContainsKey(name);
+        }
         public void ForEach(T obj, Action<string, object> action)
         {
             for (int i = 0; i < this.names.Count; i++)
         protected IList<string> refList = new List<string>();
         protected string group = null;
         void IMetaBuilder<T>.Table(string name) { this.tableName = name; }
+        private void CheckBeforeAdd(string name)
+        {
+            if (this.keys.ContainsKey(name) 
+                || this.values.ContainsKey(name)
+                || (from x in this.extraKeys.Values where x.ContainsKey(name) select x).Any() )
+            {
+                throw new Exception("Duplicate keys: " + name);
+            }
+        }
         void IKeyBuilder<T>.Key(string name, Func<T, object> getKey, Func<object, string> generator)
         {
+            this.CheckBeforeAdd(name);
             this.keys.Add(name, getKey, generator);
         }
-        IKeyBuilder<T> IMetaBuilder<T>.ExtraKey(string group)
+        void IMetaBuilder<T>.ExtraKey(string group, string name, Func<T, object> getKey, Func<object, string> generator)
         {
+            this.CheckBeforeAdd(name);
             KeysDef<T> r = null;
-            if (this.extraKeys.TryGetValue(group, out r)) return r;
-            r = new KeysDef<T>();
-            this.extraKeys.Add(group, r);
-            return r;
+            if (! this.extraKeys.TryGetValue(group, out r)) 
+            {
+                r = new KeysDef<T>();
+                this.extraKeys.Add(group, r);
+            }
+            r.Add(name, getKey, generator);
         }
         void IMetaBuilder<T>.Ref(string name, Func<T, object> getRef)
         {
+            this.CheckBeforeAdd(name);
             this.values.Add(name, getRef);
             this.refList.Add(name);
         }
         void IMetaBuilder<T>.Value(string name, Func<T, object> getValue)
         {
+            this.CheckBeforeAdd(name);
             this.values.Add(name, getValue);
         }
         void IMetaBuilder<T>.MasterExtaKey(string group)
         {
             this.ForEachInfoValue(obj, action);
         }
+        IEnumerable<string> IMetaInfo<T>.GetExtraKeyGroups()
+        {
+            return this.extraKeys.Keys.AsEnumerable();
+        }
+        IEnumerable<string> IMetaInfo<T>.GetRefList()
+        {
+            return this.refList.AsEnumerable();
+        }
     }
     public delegate void Meta<T>(IMetaBuilder<T> m);
     abstract class AbstractReconciler<OldT, NewT>
             if (r.Count != list.Count()) throw new Exception("Duplicate keys");
             return r;
         }
-        protected abstract TransactionJournal<OldT, NewT> CreateJournal(OldT o, NewT n);
+        protected virtual TransactionJournal<OldT, NewT> CreateJournal(OldT o, NewT n)
+        {
+            if (o == null && n == null) throw new Exception("To create TransactionJournal, Old and New object cannot be both null");
+            if (o == null && n != null)
+            {
+                var info = this.GetNewInfo();
+                var r = new InsertRecord(info.TableName);
+                info.ForEachInsertValue(n, (k, v) => r.Values[k] = v);
+                if (!r.Values.Any()) throw new Exception("Not enough meta information to create TransactionJournal");
+                return new TransactionJournal<OldT, NewT> { Record = r, Old = o, New = n };
+            }
+            if (o != null && n != null)
+            {
+                var oinfo = this.GetOldInfo();
+                var ninfo = this.GetNewInfo();
+                var r = new UpdateRecord(oinfo.TableName);
+                r.AtMostOne = true;
+                ninfo.ForEachKey(n, r.Keys.Add);
+                this.ForEachValueChange(o, n, (k, ov, nv) => r.Values[k] = nv);
+                if (r.Values.Any())
+                {
+                    if (!r.Keys.Any()) throw new Exception("Not enough meta information to create TransactionJournal");
+                    return new TransactionJournal<OldT, NewT> { Record = r, Old = o, New = n };
+                }
+                else
+                {
+                    return new TransactionJournal<OldT, NewT> { Record = null, Old = o, New = n };
+                }
+            }
+            if (o != null && n == null)
+            {
+                var info = this.GetOldInfo();
+                var r = new DeleteRecord(info.TableName);
+                r.AtMostOne = true;
+                info.ForEachKey(o, r.Keys.Add);
+                if (!r.Keys.Any()) throw new Exception("Not enough meta information to create TransactionJournal");
+                return new TransactionJournal<OldT, NewT> { Record = r, Old = o, New = n };
+            }
+            throw new Exception("Should not reah here");
+        }
+        protected abstract void ForEachValueChange(OldT o, NewT n, Action<string, object, object> action);
         public IEnumerable<TransactionJournal<OldT, NewT>> ReconcileInsert()
         {
             return from j in this.ReconcileNonDelete()
             this.oldLookup = CreateLookup(this.GetOldInfo(), @olds);
             this.newLookup = CreateLookup(this.GetNewInfo(), @news);
         }
-        protected override TransactionJournal<T, T> CreateJournal(T o, T n)
+        protected override void ForEachValueChange(T o, T n, Action<string, object, object> action)
         {
-            if (o == null && n == null) throw new Exception("To create TransactionJournal, Old and New object cannot be both null");
-            if (o == null && n != null)
-            {
-                var r = new InsertRecord(this.info.TableName);
-                this.info.ForEachInsertValue(n, (k, v) => r.Values[k] = v);
-                if (!r.Values.Any()) throw new Exception("Not enough meta information to create TransactionJournal");
-                return new TransactionJournal<T, T> { Record = r, Old = o, New = n };
-            }
-            if (o != null && n != null)
-            {
-                var r = new UpdateRecord(this.info.TableName);
-                r.AtMostOne = true;
-                this.info.ForEachKey(n, r.Keys.Add);
-                this.info.ForEachValueChange(o, n, (k, ov, nv) => r.Values[k] = nv);
-                if (r.Values.Any())
-                {
-                    if (!r.Keys.Any()) throw new Exception("Not enough meta information to create TransactionJournal");
-                    return new TransactionJournal<T, T> { Record = r, Old = o, New = n };
-                }
-                else
-                {
-                    return new TransactionJournal<T, T> { Record = null, Old = o, New = n };
-                }
-            }
-            if (o != null && n == null)
-            {
-                var r = new DeleteRecord(this.info.TableName);
-                r.AtMostOne = true;
-                this.info.ForEachKey(o, r.Keys.Add);
-                if (!r.Keys.Any()) throw new Exception("Not enough meta information to create TransactionJournal");
-                return new TransactionJournal<T, T> { Record = r, Old = o, New = n };
-            }
-            throw new Exception("Should not reah here");
+            this.info.ForEachValueChange(o, n, action);
         }
     }
     public class Resolver
             }
         }
     }
-    public class GenericItemList<T> where T: class
+    public class GenericItemList<T> where T : class
     {
-        private class MetaInfoAdapter : MetaInfoBuilderBase<T>
+        class GenericItemMetaInfo : IMetaInfo<object[]>
         {
-            public IMetaInfo<object[]> Adapt()
+            private IMetaInfo<T> specific = null;
+            private Dictionary<string, int> indices = null;
+            private string[] keys = null;
+            private Dictionary<string, string[]> extraKeys = null;
+            private string[] values = null;
+            private string[] refs = null;
+            public GenericItemMetaInfo(Meta<T> meta)
             {
-                var names = new List<string>();
-                var indices = new Dictionary<string, int>();
-                this.ForEachInfoValue(null, (k, v) =>
+                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[]>();
+                var @values = new List<string>();
+                int i = 0;
+                @info.ForEachKey(null, (k, v) =>
                 {
-                    if (!indices.ContainsKey(k))
+                    @indices.Add(k, i++);
+                    @keys.Add(k);
+                });
+                foreach (var g in @info.GetExtraKeyGroups())
+                {
+                    var @xkeys = new List<string>();
+                    this.specific.ForEachExtraKey(g, null, (k, v) =>
                     {
-                        indices.Add(k, names.Count);
-                        names.Add(k);
+                        @indices.Add(k, i++);
+                        @xkeys.Add(k);
+                    });
+                    @extraKeys.Add(g, @xkeys.ToArray());
+                }
+                @info.ForEachInsertValue(null, (k, v) =>
+                {
+                    if (!@indices.ContainsKey(k))
+                    {
+                        @indices.Add(k, i++);
+                        @values.Add(k);
                     }
                 });
-                Func<string, Func<object[], object>> createGetter = name =>
+                var @refs = @info.GetRefList().ToArray();
+                this.specific = @inner;
+                this.indices = @indices;
+                this.keys = @keys.ToArray();
+                this.extraKeys = @extraKeys;
+                this.values = @values.ToArray();
+                this.refs = @refs;
+            }
+            public object[] cloneItem(T source)
+            {
+                var r = new object[this.indices.Count];
+                this.specific.ForEachInsertValue(source, (k, v) =>
                 {
-                    int i = indices[name];
-                    return array => array[i];
-                };
-                var b = new MetaInfoBuilder<object[]>() as IMetaBuilder<object[]>;
-                b.Table(this.tableName);
-                this.keys.ForEach(null, (k, v) =>
+                    r[this.indices[k]] = v;
+                });
+                return r;
+            }
+            string IMetaInfo<object[]>.TableName
+            {
+                get { return this.specific.TableName; }
+            }
+            object[] IMetaInfo<object[]>.GetKey(object[] obj)
+            {
+                return obj.Take(this.keys.Length).ToArray();
+            }
+            object[] IMetaInfo<object[]>.GetKey(IDictionary<string, object> dict)
+            {
+                return (from k in this.keys select dict[k]).ToArray();
+            }
+            object[] IMetaInfo<object[]>.GetExtraKey(string group, object[] obj)
+            {
+                return (from k in this.extraKeys[@group] select obj[this.indices[k]]).ToArray();
+            }
+            object[] IMetaInfo<object[]>.GetExtraKey(string group, IDictionary<string, object> dict)
+            {
+                return (from k in this.extraKeys[@group] select dict[k]).ToArray();
+            }
+            string IMetaInfo<object[]>.GeneratorExpr(string name, object value)
+            {
+                return this.specific.GeneratorExpr(name, value);
+            }
+            void IMetaInfo<object[]>.ForEachKey(object[] obj, Action<string, object> action)
+            {
+                if (obj == null)
                 {
-                    b.Key(k, createGetter(k), value => this.keys.GeneratorExpr(k, value));
+                    this.specific.ForEachKey(null, action);
+                }
+                else
+                {
+                    int i = 0;
+                    foreach (var k in this.keys) action(k, obj[i++]);
+                }
+            }
+            void IMetaInfo<object[]>.ForEachExtraKey(string group, object[] obj, Action<string, object> action)
+            {
+                if (obj == null)
+                {
+                    this.specific.ForEachExtraKey(group, null, action);
+                }
+                else
+                {
+                    var xkeys = this.extraKeys[group];
+                    int i = this.indices[xkeys[0]];
+                    foreach (var k in xkeys) action(k, obj[i++]);
+                }
+            }
+            void IMetaInfo<object[]>.ForEachInsertValue(object[] obj, Action<string, object> action)
+            {
+                this.specific.ForEachInsertValue(null, (k, v) =>
+                {
+                    action(k, obj[this.indices[k]]);
                 });
-                foreach (var g in this.extraKeys.Keys)
+            }
+            void IMetaInfo<object[]>.ForEachValueChange(object[] o, object[] n, Action<string, object, object> action)
+            {
+                int first = this.indices[this.values[0]];
+                for (int i = 0; i < this.values.Length; i++)
                 {
-                    var source = this.extraKeys[g];
-                    var target = b.ExtraKey(g);
-                    source.ForEach(null, (k, v) =>
-                    {
-                        target.Key(k, createGetter(k), value => source.GeneratorExpr(k, value));
-                    });
+                    var ov = o[first + i];
+                    var nv = n[first + i];
+                    if (!EqualityComparer<object>.Default.Equals(ov, nv))
+                        action(this.values[i], ov, nv);
                 }
-                if (!String.IsNullOrEmpty(this.group)) b.MasterExtaKey(this.group);
-                this.values.ForEach(null, (k, v) =>
+            }
+            string IMetaInfo<object[]>.MasterKeyGroup
+            {
+                get
                 {
-                    if (this.refList.Contains(k))
-                    {
-                        b.Ref(k, createGetter(k));
-                    }
-                    else
-                    {
-                        b.Value(k, createGetter(k));
-                    }
-                });
-                return b as IMetaInfo<object[]>;
+                    return this.specific.MasterKeyGroup;
+                }
+            }
+            object[] IMetaInfo<object[]>.GetMasterRef(object[] obj)
+            {
+                if (this.refs.Length <= 0) return null;
+                var r = new object[this.refs.Length];
+                for (int i = 0; i < this.refs.Length; i++)
+                {
+                    r[i] = obj[this.indices[this.refs[i]]];
+                }
+                return r;
+            }
+            void IMetaInfo<object[]>.SetActualMasterKey(IDictionary<string, object> dict, object[] actualKey)
+            {
+                this.specific.SetActualMasterKey(dict, actualKey);
+            }
+            IEnumerable<string> IMetaInfo<object[]>.GetExtraKeyGroups()
+            {
+                return this.specific.GetExtraKeyGroups();
+            }
+
+            IEnumerable<string> IMetaInfo<object[]>.GetRefList()
+            {
+                return this.specific.GetRefList();
             }
         }
-        private IMetaInfo<T> info = null;
-        private List<object[]> items = new List<object[]>();
-        private Dictionary<string, int> indexByName = null;
-        private int[] indexByNumber = null;
-        private void BuildValueNames(T obj)
+        class GenericItemReconciler: AbstractReconciler<object[], T>
         {
-            if (this.indexByName == null)
+            protected override IMetaInfo<object[]> GetOldInfo()
             {
-                var byName = new Dictionary<string, int>();
-                var byNumber = new List<int>();
-                this.info.ForEachInsertValue(obj, (k, v) =>
-                {
-                    var i = byName.ContainsKey(k) ? byName[k] : byName.Count;
-                    byNumber.Add(i);
-                    byName[k] = i;
-                });
-                this.indexByName = byName;
-                this.indexByNumber = byNumber.ToArray();
+                throw new NotImplementedException();
+            }
+            protected override IMetaInfo<T> GetNewInfo()
+            {
+                throw new NotImplementedException();
+            }
+            protected override IDictionary<object[], object[]> GetOldLookup()
+            {
+                throw new NotImplementedException();
+            }
+            protected override IDictionary<object[], T> GetNewLookup()
+            {
+                throw new NotImplementedException();
+            }
+            protected override IEnumerable<object[]> GetOlds()
+            {
+                throw new NotImplementedException();
+            }
+            protected override IEnumerable<T> GetNews()
+            {
+                throw new NotImplementedException();
+            }
+            protected override TransactionJournal<object[], T> CreateJournal(object[] o, T n)
+            {
+                throw new NotImplementedException();
+            }
+            protected override void ForEachValueChange(object[] o, T n, Action<string, object, object> action)
+            {
+                throw new NotImplementedException();
             }
         }
-        public GenericItemList(IMetaInfo<T> info)
+        private List<object[]> items = new List<object[]>(); 
+        private GenericItemMetaInfo info = null;
+        public GenericItemList(Meta<T> meta)
         {
-            this.info = info;
+            this.info = new GenericItemMetaInfo(meta);
         }
-        private static bool FAST = true;
         public object[] Add(T obj)
         {
-            this.BuildValueNames(obj);
-            var item = new object[this.indexByName.Count];
-            int i = 0;
-            if (FAST)
-            {
-                this.info.ForEachInsertValue(obj, (k, v) => item[this.indexByNumber[i++]] = v);
-            }
-            else
-            {
-                this.info.ForEachInsertValue(obj, (k, v) => item[this.indexByName[k]] = v);
-            }
+            var item = this.info.cloneItem(obj);
             this.items.Add(item);
             return item;
         }
         {
             this.items.Clear();
         }
-        public int Count { get { return this.items.Count; } }
-        public void ForEach(Action<object[]> action)
-        {
-            this.items.ForEach(action);
-        }
-        public static Meta<object[]> GetMeta(Meta<T> inner)
-        {
-            //      public delegate void Meta<T>(IMetaBuilder<T> m);
-            return m =>
-            {
-                //inner(
-            };
-            //Action<object[]>
+        public int Count 
+        { 
+            get { return this.items.Count; } 
         }
     }
     public class Settler<T> where T : class

File UsuallyTests/TestResolve.cs

         {
             m.Table("ORDER_LINES");
             m.IntegerKey("LINE_ID", (x) => x.LineId, "SEQ_ORDER_LINES");
-            m.ExtraKey("x").DecimalKey("LINE_UNIQUE_ID", (x) => x.UniqueId, "SEQ_ORDER_LINES_UNQ");
+            m.ExtraDecimalKey("x", "LINE_UNIQUE_ID", (x) => x.UniqueId, "SEQ_ORDER_LINES_UNQ");
             m.Ref("ORDER_ID", (x) => x.OrderId);
             m.Value("ITEM_ID", (x) => x.ItemId);
             m.Value("ITEM_NAME", (x) => x.ItemName);