public string Apply(IDocumentStore store)
        {
#pragma warning disable 618
            store.Conventions.DefaultQueryingConsistency = ConsistencyOptions.AlwaysWaitForNonStaleResultsAsOfLastWrite;
#pragma warning restore 618

            var stats = new MigrationStats();

            int           retrievedResults;
            var           currentPage = 0;
            List <string> toBeDeleted = new List <string>();

            do
            {
                using (var session = store.OpenSession())
                {
                    var failedMessages = session.Advanced.LoadStartingWith <FailedMessage>(
                        $"FailedMessages/",
                        start: PageSize * currentPage++,
                        pageSize: PageSize);

                    foreach (var failedMessage in failedMessages)
                    {
                        stats += MigrateFromTemporaryCollection(failedMessage, session, toBeDeleted);
                    }

                    session.SaveChanges();

                    retrievedResults = failedMessages.Length;
                }
            } while (retrievedResults > 0);

            foreach (var key in toBeDeleted)
            {
                store.DatabaseCommands.Delete(key, null);
                stats.Deleted++;
            }

            return($"Found {stats.FoundProblem} issue(s) in {stats.Checked} Failed Message document(s). Created {stats.Created} new document(s). Deleted {stats.Deleted} old document(s).");
        }
        private MigrationStats MigrateFromTemporaryCollection(FailedMessage originalFailedMessage, IDocumentSession session, List <string> toBeDeleted)
        {
            var stats = new MigrationStats();

            if (originalFailedMessage.ProcessingAttempts.Any(x => x.MessageMetadata.ContainsKey(SplitFromUniqueMessageIdHeader)))
            {
                return(stats);
            }

            var originalStatus = originalFailedMessage.Status;

            stats.Checked = 1;

            var processingAttempts = originalFailedMessage.ProcessingAttempts
                                     .Select((a, i) => new ProcessingAttemptRecord(a, i))
                                     .ToArray();

            //Split the original FailedMessage into separate documents based on new unique message id
            var failedMessages = processingAttempts
                                 .GroupBy(p => p.UniqueMessageId)
                                 .Select(g => new FailedMessage
            {
                Id = FailedMessage.MakeDocumentId(g.Key),
                UniqueMessageId    = g.Key,
                ProcessingAttempts = g.OrderBy(a => a.Index).Select(a => a.Attempt).ToList(),
                Status             = FailedMessageStatus.Unresolved
            }).ToList();

            //Do nothing if we don't split the document
            if (failedMessages.Count == 1)
            {
                return(stats);
            }

            stats.FoundProblem++;

            if (failedMessages.All(f => f.UniqueMessageId != originalFailedMessage.UniqueMessageId))
            {
                toBeDeleted.Add(session.Advanced.GetDocumentId(originalFailedMessage));
            }
            else
            {
                var failedMessageCopy = failedMessages.Single(f => f.UniqueMessageId == originalFailedMessage.UniqueMessageId);
                failedMessages.Remove(failedMessageCopy);
                failedMessages.Add(originalFailedMessage);

                originalFailedMessage.ProcessingAttempts = failedMessageCopy.ProcessingAttempts;
                originalFailedMessage.Status             = failedMessageCopy.Status;
            }

            failedMessages.ForEach(failedMessage =>
            {
                var lastAttempt = failedMessage.ProcessingAttempts.Last();

                var messageType = GetMessageType(lastAttempt) ?? "Unknown Message Type";

                failedMessage.FailureGroups = CreateFailureGroups(messageType, lastAttempt).ToList();

                if (failedMessage.UniqueMessageId == originalFailedMessage.UniqueMessageId)
                {
                    return;
                }

                foreach (var processingAttempt in failedMessage.ProcessingAttempts)
                {
                    processingAttempt.MessageMetadata[SplitFromUniqueMessageIdHeader] = originalFailedMessage.UniqueMessageId;
                    processingAttempt.MessageMetadata[OriginalStatusHeader]           = originalStatus;
                }

                session.Store(failedMessage);
                stats.Created++;
            });

            return(stats);
        }