PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/MongoDB.Driver.Tests/Linq/Translators/AggregateProjectionTranslatorTests_Group.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 323 lines | 231 code | 78 blank | 14 comment | 1 complexity | d3e69f644819613c37d983c18893c91d MD5 | raw file
Possible License(s): Apache-2.0
  1. /* Copyright 2010-2014 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Linq;
  18. using System.Linq.Expressions;
  19. using System.Text;
  20. using System.Threading.Tasks;
  21. using MongoDB.Bson.Serialization;
  22. using MongoDB.Driver;
  23. using MongoDB.Driver.Linq.Translators;
  24. using NUnit.Framework;
  25. using FluentAssertions;
  26. using MongoDB.Bson.IO;
  27. using MongoDB.Bson;
  28. using MongoDB.Driver.Tests;
  29. namespace MongoDB.Driver.Tests.Linq.Translators
  30. {
  31. [TestFixture]
  32. public class AggregateProjectionTranslatorTests_Group : IntegrationTestBase
  33. {
  34. [Test]
  35. public async Task Should_translate_using_non_anonymous_type_with_default_constructor()
  36. {
  37. var result = await Group(x => x.A, g => new RootView { Property = g.Key, Field = g.First().B });
  38. result.Projection.Should().Be("{ _id: \"$A\", Field: { \"$first\" : \"$B\" } }");
  39. result.Value.Property.Should().Be("Amazing");
  40. result.Value.Field.Should().Be("Baby");
  41. }
  42. [Test]
  43. public async Task Should_translate_using_non_anonymous_type_with_parameterized_constructor()
  44. {
  45. var result = await Group(x => x.A, g => new RootView(g.Key) { Field = g.First().B });
  46. result.Projection.Should().Be("{ _id: \"$A\", Field: { \"$first\" : \"$B\" } }");
  47. result.Value.Property.Should().Be("Amazing");
  48. result.Value.Field.Should().Be("Baby");
  49. }
  50. [Test]
  51. public async Task Should_translate_just_id()
  52. {
  53. var result = await Group(x => x.A, g => new { _id = g.Key });
  54. result.Projection.Should().Be("{ _id: \"$A\" }");
  55. result.Value._id.Should().Be("Amazing");
  56. }
  57. [Test]
  58. public async Task Should_translate_id_when_not_named_specifically()
  59. {
  60. var result = await Group(x => x.A, g => new { Test = g.Key });
  61. result.Projection.Should().Be("{ _id: \"$A\" }");
  62. result.Value.Test.Should().Be("Amazing");
  63. }
  64. [Test]
  65. public async Task Should_translate_addToSet()
  66. {
  67. var result = await Group(x => x.A, g => new { Result = new HashSet<int>(g.Select(x => x.C.E.F)) });
  68. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$addToSet\": \"$C.E.F\" } }");
  69. result.Value.Result.Should().Equal(111);
  70. }
  71. [Test]
  72. public async Task Should_translate_addToSet_using_Distinct()
  73. {
  74. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F).Distinct() });
  75. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$addToSet\": \"$C.E.F\" } }");
  76. result.Value.Result.Should().Equal(111);
  77. }
  78. [Test]
  79. public async Task Should_translate_average_with_embedded_projector()
  80. {
  81. var result = await Group(x => x.A, g => new { Result = g.Average(x => x.C.E.F) });
  82. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$avg\": \"$C.E.F\" } }");
  83. result.Value.Result.Should().Be(111);
  84. }
  85. [Test]
  86. public async Task Should_translate_average_with_selected_projector()
  87. {
  88. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F).Average() });
  89. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$avg\": \"$C.E.F\" } }");
  90. result.Value.Result.Should().Be(111);
  91. }
  92. [Test]
  93. public async Task Should_translate_count()
  94. {
  95. var result = await Group(x => x.A, g => new { Result = g.Count() });
  96. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$sum\": 1 } }");
  97. result.Value.Result.Should().Be(1);
  98. }
  99. [Test]
  100. public async Task Should_translate_long_count()
  101. {
  102. var result = await Group(x => x.A, g => new { Result = g.LongCount() });
  103. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$sum\": 1 } }");
  104. result.Value.Result.Should().Be(1);
  105. }
  106. [Test]
  107. public async Task Should_translate_first()
  108. {
  109. var result = await Group(x => x.A, g => new { B = g.Select(x => x.B).First() });
  110. result.Projection.Should().Be("{ _id: \"$A\", B: { \"$first\": \"$B\" } }");
  111. result.Value.B.Should().Be("Baby");
  112. }
  113. [Test]
  114. public async Task Should_translate_first_with_normalization()
  115. {
  116. var result = await Group(x => x.A, g => new { g.First().B });
  117. result.Projection.Should().Be("{ _id: \"$A\", B: { \"$first\": \"$B\" } }");
  118. result.Value.B.Should().Be("Baby");
  119. }
  120. [Test]
  121. public async Task Should_translate_last()
  122. {
  123. var result = await Group(x => x.A, g => new { B = g.Select(x => x.B).Last() });
  124. result.Projection.Should().Be("{ _id: \"$A\", B: { \"$last\": \"$B\" } }");
  125. result.Value.B.Should().Be("Baby");
  126. }
  127. [Test]
  128. public async Task Should_translate_last_with_normalization()
  129. {
  130. var result = await Group(x => x.A, g => new { g.Last().B });
  131. result.Projection.Should().Be("{ _id: \"$A\", B: { \"$last\": \"$B\" } }");
  132. result.Value.B.Should().Be("Baby");
  133. }
  134. [Test]
  135. public void Should_throw_an_exception_when_last_is_used_with_a_predicate()
  136. {
  137. Func<Task> act = () => Group(x => x.A, g => new { g.Last(x => x.A == "bin").B });
  138. act.ShouldThrow<NotSupportedException>();
  139. }
  140. [Test]
  141. public async Task Should_translate_max_with_embedded_projector()
  142. {
  143. var result = await Group(x => x.A, g => new { Result = g.Max(x => x.C.E.F) });
  144. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$max\": \"$C.E.F\" } }");
  145. result.Value.Result.Should().Be(111);
  146. }
  147. [Test]
  148. public async Task Should_translate_max_with_selected_projector()
  149. {
  150. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F).Max() });
  151. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$max\": \"$C.E.F\" } }");
  152. result.Value.Result.Should().Be(111);
  153. }
  154. [Test]
  155. public async Task Should_translate_min_with_embedded_projector()
  156. {
  157. var result = await Group(x => x.A, g => new { Result = g.Min(x => x.C.E.F) });
  158. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$min\": \"$C.E.F\" } }");
  159. result.Value.Result.Should().Be(111);
  160. }
  161. [Test]
  162. public async Task Should_translate_min_with_selected_projector()
  163. {
  164. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F).Min() });
  165. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$min\": \"$C.E.F\" } }");
  166. result.Value.Result.Should().Be(111);
  167. }
  168. [Test]
  169. public async Task Should_translate_push_with_just_a_select()
  170. {
  171. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F) });
  172. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$push\": \"$C.E.F\" } }");
  173. result.Value.Result.Should().Equal(111);
  174. }
  175. [Test]
  176. public async Task Should_translate_push_with_ToArray()
  177. {
  178. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F).ToArray() });
  179. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$push\": \"$C.E.F\" } }");
  180. result.Value.Result.Should().Equal(111);
  181. }
  182. [Test]
  183. public async Task Should_translate_push_with_ToList()
  184. {
  185. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F).ToList() });
  186. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$push\": \"$C.E.F\" } }");
  187. result.Value.Result.Should().Equal(111);
  188. }
  189. [Test]
  190. public async Task Should_translate_sum_with_embedded_projector()
  191. {
  192. var result = await Group(x => x.A, g => new { Result = g.Sum(x => x.C.E.F) });
  193. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$sum\": \"$C.E.F\" } }");
  194. result.Value.Result.Should().Be(111);
  195. }
  196. [Test]
  197. public async Task Should_translate_sum_with_selected_projector()
  198. {
  199. var result = await Group(x => x.A, g => new { Result = g.Select(x => x.C.E.F).Sum() });
  200. result.Projection.Should().Be("{ _id: \"$A\", Result: { \"$sum\": \"$C.E.F\" } }");
  201. result.Value.Result.Should().Be(111);
  202. }
  203. [Test]
  204. public async Task Should_translate_complex_selector()
  205. {
  206. var result = await Group(x => x.A, g => new
  207. {
  208. Count = g.Count(),
  209. Sum = g.Sum(x => x.C.E.F + x.C.E.H),
  210. First = g.First().B,
  211. Last = g.Last().K,
  212. Min = g.Min(x => x.C.E.F + x.C.E.H),
  213. Max = g.Max(x => x.C.E.F + x.C.E.H)
  214. });
  215. result.Projection.Should().Be("{ _id : \"$A\", Count : { \"$sum\" : 1 }, Sum : { \"$sum\" : { \"$add\": [\"$C.E.F\", \"$C.E.H\"] } }, First : { \"$first\" : \"$B\" }, Last : { \"$last\" : \"$K\" }, Min : { \"$min\" : { \"$add\" : [\"$C.E.F\", \"$C.E.H\"] } }, Max : { \"$max\" : { \"$add\" : [\"$C.E.F\", \"$C.E.H\"] } } }");
  216. result.Value.Count.Should().Be(1);
  217. result.Value.Sum.Should().Be(333);
  218. result.Value.First.Should().Be("Baby");
  219. result.Value.Last.Should().Be(false);
  220. result.Value.Min.Should().Be(333);
  221. result.Value.Max.Should().Be(333);
  222. }
  223. private async Task<ProjectedResult<TResult>> Group<TKey, TResult>(Expression<Func<Root, TKey>> idProjector, Expression<Func<IGrouping<TKey, Root>, TResult>> groupProjector)
  224. {
  225. var serializer = BsonSerializer.SerializerRegistry.GetSerializer<Root>();
  226. var projectionInfo = AggregateProjectionTranslator.TranslateGroup<TKey, Root, TResult>(idProjector, groupProjector, serializer, BsonSerializer.SerializerRegistry);
  227. var group = new BsonDocument("$group", projectionInfo.Document);
  228. var sort = new BsonDocument("$sort", new BsonDocument("_id", 1));
  229. using (var cursor = await _collection.AggregateAsync<TResult>(new BsonDocumentStagePipelineDefinition<Root, TResult>(new[] { group, sort }, projectionInfo.ProjectionSerializer)))
  230. {
  231. var list = await cursor.ToListAsync();
  232. return new ProjectedResult<TResult>
  233. {
  234. Projection = projectionInfo.Document,
  235. Value = (TResult)list[0]
  236. };
  237. }
  238. }
  239. private class ProjectedResult<T>
  240. {
  241. public BsonDocument Projection;
  242. public T Value;
  243. }
  244. }
  245. }