PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Oak/DynamicModels.cs

https://github.com/lefthandedgoat/Oak
C# | 241 lines | 176 code | 65 blank | 0 comment | 16 complexity | 40a8f25b94f18341ca7ac57c13563fec MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Collections;
  6. using System.Dynamic;
  7. namespace Oak
  8. {
  9. public static class DynamicModelExtensions
  10. {
  11. public static DynamicModels ToModels(this IEnumerable<dynamic> enumerable)
  12. {
  13. return new DynamicModels(enumerable);
  14. }
  15. }
  16. public class DynamicModels : Gemini, IEnumerable<object>
  17. {
  18. public List<dynamic> Models { get; set; }
  19. public DynamicModels(IEnumerable<dynamic> models)
  20. {
  21. Models = models.ToList();
  22. }
  23. public new IEnumerable<dynamic> Select(params string[] properties)
  24. {
  25. foreach (dynamic model in Models) yield return Select(model, properties);
  26. }
  27. dynamic Select(dynamic model, params string[] properties)
  28. {
  29. var hash = (model as object).ToDictionary();
  30. var prototype = new Prototype() as IDictionary<string, object>;
  31. hash.Where(s => properties.Contains(s.Key)).ForEach(kvp => prototype.Add(kvp.Key, kvp.Value));
  32. if (prototype.Count == 1) return prototype.First().Value;
  33. return prototype;
  34. }
  35. public bool Any(dynamic options)
  36. {
  37. options = (options as object).ToPrototype();
  38. foreach (dynamic model in Models) if (IsMatch(options, model)) return true;
  39. return false;
  40. }
  41. public List<dynamic> ToList()
  42. {
  43. return new List<dynamic>(Models);
  44. }
  45. public bool Any()
  46. {
  47. return Models.Any();
  48. }
  49. public int Count()
  50. {
  51. return Models.Count;
  52. }
  53. public dynamic First()
  54. {
  55. return Models.FirstOrDefault();
  56. }
  57. public dynamic Second()
  58. {
  59. if (Models.Count >= 2) return Models[1];
  60. return null;
  61. }
  62. public dynamic Last()
  63. {
  64. return Models.LastOrDefault();
  65. }
  66. public dynamic Last(dynamic options)
  67. {
  68. return Where(options as object).LastOrDefault();
  69. }
  70. public dynamic First(dynamic options)
  71. {
  72. return Where(options as object).FirstOrDefault();
  73. }
  74. public dynamic OrderBy(dynamic options)
  75. {
  76. var dict = (options as object).ToPrototype() as IDictionary<string, object>;
  77. dynamic results = Models.AsEnumerable();
  78. dict.ForEach(kvp => results = Sort(results, kvp.Key, kvp.Value));
  79. return new DynamicModels(results);
  80. }
  81. public dynamic Sort(IEnumerable<dynamic> models, string property, object direction)
  82. {
  83. if (models is IOrderedEnumerable<dynamic>)
  84. {
  85. var ordered = (models as IOrderedEnumerable<dynamic>);
  86. if (IsAscending(direction)) return ordered.ThenBy(s => ValueFor(s, property));
  87. return ordered.ThenByDescending(s => ValueFor(s, property));
  88. }
  89. if (IsAscending(direction)) return models.OrderBy(s => ValueFor(s, property));
  90. return models.OrderByDescending(s => ValueFor(s, property));
  91. }
  92. public dynamic ValueFor(dynamic model, string property)
  93. {
  94. return ValueFor((ToHash(model) as IDictionary<string, object>)[property]);
  95. }
  96. public bool IsAscending(object value)
  97. {
  98. return (value as string) == "asc";
  99. }
  100. public DynamicModels Where(dynamic options)
  101. {
  102. options = (options as object).ToPrototype();
  103. var results = new List<dynamic>();
  104. foreach (dynamic model in Models) if (IsMatch(options, model)) results.Add(model);
  105. return new DynamicModels(results);
  106. }
  107. private bool IsMatch(IDictionary<string, dynamic> options, dynamic model)
  108. {
  109. IDictionary<string, object> hash = ToHash(model);
  110. return options.All(s => s.Value == ValueFor(hash[s.Key]));
  111. }
  112. private IDictionary<string, object> ToHash(dynamic model)
  113. {
  114. if (model is Gemini) return model.Hash();
  115. return (model as object).ToPrototype();
  116. }
  117. private dynamic ValueFor(dynamic value)
  118. {
  119. if (value is Delegate) return value();
  120. return value;
  121. }
  122. public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
  123. {
  124. if (RespondsTo(binder.Name)) return base.TryInvokeMember(binder, args, out result);
  125. return EagerLoad(binder.Name, args, out result);
  126. }
  127. private bool EagerLoad(string collectionName, object[] args, out object result)
  128. {
  129. result = new HashSet<dynamic>();
  130. if (!Models.Any()) return true;
  131. dynamic options = null;
  132. if (args.Any()) options = args[0];
  133. foreach(var m in Models)
  134. {
  135. var association = m.AssociationNamed(collectionName);
  136. IEnumerable<dynamic> values = association.EagerLoad(Models, options);
  137. foreach(var v in values) (result as HashSet<dynamic>).Add(v);
  138. if(association is SingleAssociation) break;
  139. }
  140. result = new DynamicModels(result as HashSet<dynamic>);
  141. return true;
  142. }
  143. private dynamic Get(string collectionName, dynamic model)
  144. {
  145. return model.GetMember(collectionName).Invoke(null);
  146. }
  147. public IEnumerator<object> GetEnumerator()
  148. {
  149. return Models.GetEnumerator();
  150. }
  151. public DynamicModels Include(params string[] methods)
  152. {
  153. var result = new object();
  154. methods.ForEach(s =>
  155. {
  156. EagerLoad(s, new object[] { }, out result);
  157. });
  158. return this;
  159. }
  160. IEnumerator IEnumerable.GetEnumerator()
  161. {
  162. return Models.GetEnumerator();
  163. }
  164. public override string ToString()
  165. {
  166. var fullString = base.ToString();
  167. fullString += "========= Entries ===========" + Environment.NewLine;
  168. foreach (var model in Models)
  169. {
  170. fullString += model + Environment.NewLine;
  171. }
  172. fullString += "=============================" + Environment.NewLine;
  173. return fullString;
  174. }
  175. }
  176. }