/ToMigrate/Raven.Tests.Issues/RavenDB_1601.cs

https://github.com/fitzchak/ravendb · C# · 514 lines · 443 code · 64 blank · 7 comment · 4 complexity · 5fc3176b651e2fcb26acd46487fc15cd MD5 · raw file

  1. // -----------------------------------------------------------------------
  2. // <copyright file="RavenDB_1601.cs" company="Hibernating Rhinos LTD">
  3. // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4. // </copyright>
  5. // -----------------------------------------------------------------------
  6. using System;
  7. using System.Collections.Generic;
  8. using Raven.Abstractions.Data;
  9. using Raven.Abstractions.Indexing;
  10. using Raven.Client;
  11. using Raven.Client.Indexes;
  12. using Raven.Database.Bundles.ScriptedIndexResults;
  13. using Raven.Database.Json;
  14. using Raven.Json.Linq;
  15. using Raven.Tests.Bundles.ScriptedIndexResults;
  16. using Raven.Tests.Common;
  17. using Xunit;
  18. using Raven.Client.Linq;
  19. using System.Linq;
  20. namespace Raven.Tests.Issues
  21. {
  22. public class RavenDB_1601 : RavenTest
  23. {
  24. protected override void ModifyConfiguration(Database.Config.InMemoryRavenConfiguration configuration)
  25. {
  26. configuration.Settings["Raven/ActiveBundles"] = "ScriptedIndexResults";
  27. }
  28. public class Developer
  29. {
  30. public string Id { get; set; }
  31. public string Name { get; set; }
  32. public List<Skill> Skills { get; set; }
  33. }
  34. public class SkillStat
  35. {
  36. public string Id { get; set; }
  37. public int Count { get; set; }
  38. }
  39. public class Skill
  40. {
  41. public Skill()
  42. {
  43. }
  44. public Skill(string name)
  45. {
  46. Name = name;
  47. }
  48. public string Name { get; set; }
  49. }
  50. public class OpCounter
  51. {
  52. public int Index { get; set; }
  53. public int Deletes { get; set; }
  54. }
  55. private void VerifyOperationsCount(IDocumentSession session, int expectedMinIndexInvocations, int expectedMinDeleteInvocations)
  56. {
  57. var opCounter = session.Load<RavenJObject>("opCounter");
  58. Assert.True(expectedMinIndexInvocations <= opCounter.Value<int>("Index"));
  59. Assert.True(expectedMinDeleteInvocations <= opCounter.Value<int>("Deletes"));
  60. }
  61. [Fact]
  62. public void CanUpdateRemoveValuesOnDocumentInSimpleIndexMultipleValues()
  63. {
  64. using (var store = NewRemoteDocumentStore())
  65. {
  66. using (var s = store.OpenSession())
  67. {
  68. s.Store(new ScriptedIndexResults
  69. {
  70. Id = ScriptedIndexResults.IdPrefix + new Developers_Skills().IndexName,
  71. IndexScript = @"
  72. var docId = 'Skills/'+ this.Skill;
  73. var type = LoadDocument(docId) || {};
  74. type.Count++;
  75. var opCounterId = 'opCounter';
  76. var opCounter = LoadDocument(opCounterId) || {};
  77. opCounter.Index++;
  78. PutDocument(opCounterId, opCounter);
  79. PutDocument(docId, type);",
  80. DeleteScript = @"
  81. var docId = 'Skills/'+ this.Skill;
  82. var type = LoadDocument(docId);
  83. if(type == null)
  84. return;
  85. var opCounterId = 'opCounter';
  86. var opCounter = LoadDocument(opCounterId) || {};
  87. opCounter.Deletes++;
  88. PutDocument(opCounterId, opCounter);
  89. type.Count--;
  90. PutDocument(docId, type);
  91. "
  92. });
  93. s.SaveChanges();
  94. }
  95. using (var s = store.OpenSession())
  96. {
  97. s.Store(new Developer
  98. {
  99. Name = "marcin",
  100. Skills = new List<Skill>
  101. {
  102. new Skill("java"),
  103. new Skill("NET")
  104. }
  105. });
  106. s.Store(new Developer
  107. {
  108. Name = "john",
  109. Skills = new List<Skill>
  110. {
  111. new Skill("NET")
  112. }
  113. });
  114. s.Store(new OpCounter(), "opCounter");
  115. s.Store(new SkillStat
  116. {
  117. Id = "Skills/NET",
  118. Count = 0
  119. });
  120. s.Store(new SkillStat
  121. {
  122. Id = "Skills/Java",
  123. Count = 0
  124. });
  125. s.SaveChanges();
  126. }
  127. new Developers_Skills().Execute(store);
  128. WaitForIndexing(store);
  129. using (var s = store.OpenSession())
  130. {
  131. VerifyOperationsCount(s, 3, 0);
  132. Assert.Equal(2, s.Load<SkillStat>("Skills/NET").Count);
  133. Assert.Equal(1, s.Load<SkillStat>("Skills/Java").Count);
  134. }
  135. store.DatabaseCommands.Delete("developers/1", null);
  136. WaitForIndexing(store);
  137. using (var s = store.OpenSession())
  138. {
  139. VerifyOperationsCount(s, 3, 2);
  140. Assert.Equal(1, s.Load<SkillStat>("Skills/NET").Count);
  141. Assert.Equal(0, s.Load<SkillStat>("Skills/Java").Count);
  142. }
  143. }
  144. }
  145. [Fact]
  146. public void CanUpdateRemoveValuesOnDocumentInSimpleIndex()
  147. {
  148. using (var store = NewDocumentStore())
  149. {
  150. using (var s = store.OpenSession())
  151. {
  152. s.Store(new ScriptedIndexResults
  153. {
  154. Id = ScriptedIndexResults.IdPrefix + new Animals_Simple().IndexName,
  155. IndexScript = @"
  156. var docId = 'AnimalTypes/'+ this.Type;
  157. var type = LoadDocument(docId) || {};
  158. type.Count++;
  159. var opCounterId = 'opCounter';
  160. var opCounter = LoadDocument(opCounterId) || {};
  161. opCounter.Index++;
  162. PutDocument(opCounterId, opCounter);
  163. PutDocument(docId, type);",
  164. DeleteScript = @"
  165. var docId = 'AnimalTypes/'+ this.Type;
  166. var type = LoadDocument(docId);
  167. if(type == null)
  168. return;
  169. var opCounterId = 'opCounter';
  170. var opCounter = LoadDocument(opCounterId) || {};
  171. opCounter.Deletes++;
  172. PutDocument(opCounterId, opCounter);
  173. type.Count--;
  174. PutDocument(docId, type);
  175. "
  176. });
  177. s.SaveChanges();
  178. }
  179. using (var s = store.OpenSession())
  180. {
  181. s.Store(new Animal
  182. {
  183. Name = "Arava",
  184. Type = "Dog"
  185. });
  186. s.Store(new Animal
  187. {
  188. Name = "Oscar",
  189. Type = "Dog"
  190. });
  191. s.Store(new Animal
  192. {
  193. Name = "Pluto",
  194. Type = "Dog"
  195. });
  196. s.Store(new OpCounter(), "opCounter");
  197. s.Store(new AnimalType
  198. {
  199. Id = "AnimalTypes/Dog",
  200. Description = "Man's Best Friend"
  201. });
  202. s.SaveChanges();
  203. }
  204. new Animals_Simple().Execute(store);
  205. WaitForIndexing(store);
  206. using (var s = store.OpenSession())
  207. {
  208. var animalType = s.Load<AnimalType>("AnimalTypes/Dog");
  209. Assert.Equal(3, animalType.Count);
  210. VerifyOperationsCount(s, 3, 0);
  211. }
  212. using (var s = store.OpenSession())
  213. {
  214. var pluto = s.Query<Animal>().Single(a => a.Name == "Pluto");
  215. s.Delete(pluto);
  216. s.SaveChanges();
  217. }
  218. WaitForIndexing(store);
  219. using (var s = store.OpenSession())
  220. {
  221. var animalType = s.Load<AnimalType>("AnimalTypes/Dog");
  222. Assert.Equal(2, animalType.Count);
  223. VerifyOperationsCount(s, 3, 1);
  224. }
  225. using (var s = store.OpenSession())
  226. {
  227. var oscar = s.Query<Animal>().Single(a => a.Name == "Oscar");
  228. s.Delete(oscar);
  229. s.Store(new Animal
  230. {
  231. Name = "Rex",
  232. Type = "Dog"
  233. });
  234. s.SaveChanges();
  235. }
  236. WaitForIndexing(store);
  237. using (var s = store.OpenSession())
  238. {
  239. var animalType = s.Load<AnimalType>("AnimalTypes/Dog");
  240. Assert.Equal(2, animalType.Count);
  241. VerifyOperationsCount(s, 4, 2);
  242. }
  243. }
  244. }
  245. public class Animals_Simple : AbstractIndexCreationTask<Animal, Animals_Simple.Result>
  246. {
  247. public class Result
  248. {
  249. public string Type { get; set; }
  250. }
  251. public Animals_Simple()
  252. {
  253. Map = animals =>
  254. from animal in animals
  255. select new
  256. {
  257. animal.Type
  258. };
  259. Store(a => a.Type, FieldStorage.Yes);
  260. }
  261. }
  262. public class Developers_Skills : AbstractIndexCreationTask<Developer, Developers_Skills.Result>
  263. {
  264. public class Result
  265. {
  266. public string Skill { get; set; }
  267. }
  268. public Developers_Skills()
  269. {
  270. Map = developers => from developer in developers from skill in developer.Skills select new Result { Skill = skill.Name };
  271. Store(s => s.Skill, FieldStorage.Yes);
  272. }
  273. }
  274. [Fact]
  275. public void CanUpdateValueOnDocumentInMapReduce()
  276. {
  277. using (var store = NewDocumentStore())
  278. {
  279. using (var s = store.OpenSession())
  280. {
  281. s.Store(new ScriptedIndexResults
  282. {
  283. Id = ScriptedIndexResults.IdPrefix + new Animals_Stats().IndexName,
  284. IndexScript = @"
  285. var docId = 'AnimalTypes/'+ key;
  286. var type = LoadDocument(docId) || {};
  287. type.Count = this.Count;
  288. var opCounterId = 'opCounter';
  289. var opCounter = LoadDocument(opCounterId) || {};
  290. opCounter.Index++;
  291. PutDocument(opCounterId, opCounter);
  292. PutDocument(docId, type);",
  293. DeleteScript = @"
  294. var docId = 'AnimalTypes/'+ key;
  295. var type = LoadDocument(docId);
  296. if(type == null)
  297. return;
  298. var opCounterId = 'opCounter';
  299. var opCounter = LoadDocument(opCounterId) || {};
  300. opCounter.Deletes++;
  301. PutDocument(opCounterId, opCounter);
  302. type.Count = 0;
  303. PutDocument(docId, type);
  304. "
  305. });
  306. s.SaveChanges();
  307. }
  308. using (var s = store.OpenSession())
  309. {
  310. s.Store(new Animal
  311. {
  312. Name = "Arava",
  313. Type = "Dog"
  314. });
  315. s.Store(new Animal
  316. {
  317. Name = "Oscar",
  318. Type = "Dog"
  319. });
  320. s.Store(new OpCounter(), "opCounter");
  321. s.Store(new AnimalType
  322. {
  323. Id = "AnimalTypes/Dog",
  324. Description = "Man's Best Friend"
  325. });
  326. s.SaveChanges();
  327. }
  328. new Animals_Stats().Execute(store);
  329. WaitForIndexing(store);
  330. using (var s = store.OpenSession())
  331. {
  332. // one bucket (dog) => one insert
  333. VerifyOperationsCount(s, 1, 0);
  334. var animalType = s.Load<AnimalType>("AnimalTypes/Dog");
  335. Assert.Equal(2, animalType.Count);
  336. }
  337. using (var s = store.OpenSession())
  338. {
  339. s.Store(new Animal
  340. {
  341. Name = "Rex",
  342. Type = "Dog"
  343. });
  344. s.SaveChanges();
  345. }
  346. WaitForIndexing(store);
  347. using (var s = store.OpenSession())
  348. {
  349. VerifyOperationsCount(s, 2, 1);
  350. var animalType = s.Load<AnimalType>("AnimalTypes/Dog");
  351. Assert.Equal(3, animalType.Count);
  352. }
  353. using (var s = store.OpenSession())
  354. {
  355. s.Store(new Animal
  356. {
  357. Name = "Ara",
  358. Type = "Parrot"
  359. });
  360. s.Store(new Animal
  361. {
  362. Name = "Pluto",
  363. Type = "Dog"
  364. });
  365. s.SaveChanges();
  366. }
  367. WaitForIndexing(store);
  368. using (var s = store.OpenSession())
  369. {
  370. VerifyOperationsCount(s, 4, 2);
  371. var animalType = s.Load<AnimalType>("AnimalTypes/Dog");
  372. Assert.Equal(4, animalType.Count);
  373. var parrotType = s.Load<AnimalType>("AnimalTypes/Parrot");
  374. Assert.Equal(1, parrotType.Count);
  375. }
  376. using (var s = store.OpenSession())
  377. {
  378. var dogs = s.Query<Animal>().Where(a => a.Type == "Dog");
  379. foreach (var dog in dogs)
  380. {
  381. s.Delete(dog);
  382. }
  383. s.SaveChanges();
  384. }
  385. WaitForIndexing(store);
  386. using (var s = store.OpenSession())
  387. {
  388. // one bucket (dog) => one insert
  389. VerifyOperationsCount(s, 4, 3);
  390. var animalType = s.Load<AnimalType>("AnimalTypes/Dog");
  391. Assert.Equal(0, animalType.Count);
  392. var parrotType = s.Load<AnimalType>("AnimalTypes/Parrot");
  393. Assert.Equal(1, parrotType.Count);
  394. }
  395. }
  396. }
  397. [Fact]
  398. public void CanLoadPutDocumentsMultipleTimesInPatcher()
  399. {
  400. using (var store = NewDocumentStore())
  401. {
  402. using (var s = store.OpenSession())
  403. {
  404. s.Store(new OpCounter(), "opCounter");
  405. s.SaveChanges();
  406. }
  407. var patcher = new ScriptedJsonPatcher(store.SystemDatabase);
  408. using (var scope = new ScriptedIndexResultsJsonPatcherScope(store.SystemDatabase, new HashSet<string> { "dogs" }))
  409. {
  410. patcher.Apply(scope, new RavenJObject(), new ScriptedPatchRequest
  411. {
  412. Script =
  413. @"var opCounterId = 'opCounter';
  414. var opCounter = LoadDocument(opCounterId) || {};
  415. opCounter.Index++;
  416. PutDocument(opCounterId, opCounter);
  417. opCounter = LoadDocument(opCounterId)
  418. opCounter.Deletes++;
  419. PutDocument(opCounterId, opCounter);
  420. "
  421. });
  422. store.SystemDatabase.TransactionalStorage.Batch(accessor =>
  423. {
  424. foreach (var operation in scope.GetOperations())
  425. {
  426. switch (operation.Type)
  427. {
  428. case ScriptedJsonPatcher.OperationType.Put:
  429. store.SystemDatabase.Documents.Put(operation.Document.Key, operation.Document.Etag, operation.Document.DataAsJson,
  430. operation.Document.Metadata, null);
  431. break;
  432. case ScriptedJsonPatcher.OperationType.Delete:
  433. store.SystemDatabase.Documents.Delete(operation.DocumentKey, null, null);
  434. break;
  435. default:
  436. throw new ArgumentOutOfRangeException("operation.Type");
  437. }
  438. }
  439. });
  440. }
  441. using (var s = store.OpenSession())
  442. {
  443. var opCounter = s.Load<OpCounter>("opCounter");
  444. Assert.Equal(1, opCounter.Deletes);
  445. Assert.Equal(1, opCounter.Index);
  446. }
  447. }
  448. }
  449. }
  450. }