/// <summary>
        /// Handles the specified query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <returns></returns>
        /// <exception cref="PoisonMessageException">An error has occured trying to re-assemble a message de-queued from SQLite</exception>
        /// <exception cref="MessageQueueId"></exception>
        public async Task <IReceivedMessageInternal> Handle(ReceiveMessageQueryAsync <IDbConnection, IDbTransaction> query)
        {
            if (!_databaseExists.Exists(_connectionInformation.ConnectionString))
            {
                return(null);
            }

            using (var connection = _dbFactory.CreateConnection(_connectionInformation.ConnectionString, false))
            {
                connection.Open();
                using (var transaction = _dbFactory.CreateTransaction(connection).BeginTransaction())
                {
                    using (var selectCommand = connection.CreateCommand())
                    {
                        selectCommand.Transaction = transaction;
                        CommandString commandString =
                            GetDeQueueCommand(_tableNameHelper.MetaDataName, _tableNameHelper.QueueName,
                                              _tableNameHelper.StatusName, query.Routes);

                        if (commandString == null)
                        {
                            throw new DotNetWorkQueueException("Failed to generate command text for de-queue of messages");
                        }

                        _buildDequeueCommand.BuildCommand(selectCommand, commandString, _options.Value, query.Routes);
                        using (var reader = await _readerAsync.ExecuteReaderAsync(selectCommand).ConfigureAwait(false))
                        {
                            return(_messageDeQueue.HandleMessage(connection, transaction, reader, commandString));
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Handles the specified query.
 /// </summary>
 /// <param name="query">The query.</param>
 /// <returns></returns>
 public async Task <IReceivedMessageInternal> Handle(ReceiveMessageQueryAsync <SqlConnection, SqlTransaction> query)
 {
     using (var selectCommand = query.Connection.CreateCommand())
     {
         _buildDequeueCommand.BuildCommand(selectCommand, query);
         using (var reader = await selectCommand.ExecuteReaderAsync().ConfigureAwait(false))
         {
             return(_readMessage.Read(reader));
         }
     }
 }
        /// <inheritdoc />
        public async Task <RedisMessage> Handle(ReceiveMessageQueryAsync query)
        {
            byte[] message = null;
            byte[] headers = null;
            string messageId;
            var    poisonMessage = false;
            RedisQueueCorrelationIdSerialized correlationId = null;

            try
            {
                var          unixTimestamp = _unixTimeFactory.Create().GetCurrentUnixTimestampMilliseconds();
                RedisValue[] result;
                if (query.MessageId != null && query.MessageId.HasValue)
                {
                    result = await _dequeueRpcLua.ExecuteAsync(query.MessageId.Id.Value.ToString(), unixTimestamp).ConfigureAwait(false);
                }
                else
                {
                    result = await _dequeueLua.ExecuteAsync(unixTimestamp).ConfigureAwait(false);
                }

                if (result == null || result.Length == 1 && !result[0].HasValue || !result[0].HasValue)
                {
                    return(null);
                }

                if (!result[1].HasValue)
                {
                    //at this point, the record has been de-queued, but it can't be processed.
                    poisonMessage = true;
                }

                messageId = result[0];
                var id = new RedisQueueId(messageId);
                query.MessageContext.MessageId = id;
                if (!poisonMessage)
                {
                    message = result[1];
                    headers = result[2];
                    if (result[3].HasValue)
                    {
                        if (result[3].TryParse(out long messageExpiration))
                        {
                            if (messageExpiration - unixTimestamp < 0)
                            {
                                //message has expired
                                _deleteMessage.Handle(new DeleteMessageCommand(new RedisQueueId(messageId)));
                                return(new RedisMessage(messageId, null, true));
                            }
                        }
                    }
                }
            }
            catch (Exception error)
            {
                throw new ReceiveMessageException("Failed to dequeue a message", error);
            }

            if (poisonMessage)
            {
                //at this point, the record has been de-queued, but it can't be processed.
                throw new PoisonMessageException(
                          "An error has occurred trying to re-assemble a message de-queued from redis; a messageId was returned, but the LUA script returned a null message. The message payload has most likely been lost.",
                          null,
                          new RedisQueueId(messageId), new RedisQueueCorrelationId(Guid.Empty),
                          null, null);
            }

            try
            {
                var allHeaders = _serializer.InternalSerializer.ConvertBytesTo <IDictionary <string, object> >(headers);
                correlationId = (RedisQueueCorrelationIdSerialized)allHeaders[_redisHeaders.CorrelationId.Name];
                var messageGraph =
                    (MessageInterceptorsGraph)
                    allHeaders[_redisHeaders.Headers.StandardHeaders.MessageInterceptorGraph.Name];
                var messageData = _serializer.Serializer.BytesToMessage <MessageBody>(message, messageGraph);

                var newMessage = _messageFactory.Create(messageData.Body, allHeaders);

                return(new RedisMessage(
                           messageId,
                           _receivedMessageFactory.Create(
                               newMessage,
                               new RedisQueueId(messageId),
                               new RedisQueueCorrelationId(correlationId.Id)), false));
            }
            catch (Exception error)
            {
                //at this point, the record has been de-queued, but it can't be processed.
                throw new PoisonMessageException(
                          "An error has occurred trying to re-assemble a message de-queued from redis", error,
                          new RedisQueueId(messageId), new RedisQueueCorrelationId(correlationId),
                          message, headers);
            }
        }
 public void BuildCommand(SqlCommand selectCommand, ReceiveMessageQueryAsync <SqlConnection, SqlTransaction> query)
 {
     BuildCommandInternal(selectCommand, query.Transaction, query.MessageId, query.Routes);
 }
        /// <inheritdoc />
        public async Task <IReceivedMessageInternal> Handle(ReceiveMessageQueryAsync <NpgsqlConnection, NpgsqlTransaction> query)
        {
            using (var selectCommand = query.Connection.CreateCommand())
            {
                selectCommand.Transaction = query.Transaction;
                if (query.MessageId != null && query.MessageId.HasValue)
                {
                    selectCommand.CommandText =
                        ReceiveMessage.GetDeQueueCommand(_commandCache, _tableNameHelper, _options.Value, true, query.Routes);
                    selectCommand.Parameters.Add("@QueueID", NpgsqlDbType.Bigint);
                    selectCommand.Parameters["@QueueID"].Value = query.MessageId.Id.Value;
                }
                else
                {
                    selectCommand.CommandText =
                        ReceiveMessage.GetDeQueueCommand(_commandCache, _tableNameHelper, _options.Value, false, query.Routes);
                }

                selectCommand.Parameters.Add("@CurrentDate", NpgsqlDbType.Bigint);
                selectCommand.Parameters["@CurrentDate"].Value = _getTime.GetCurrentUtcDate().Ticks;

                if (_options.Value.EnableRoute && query.Routes != null && query.Routes.Count > 0)
                {
                    var routeCounter = 1;
                    foreach (var route in query.Routes)
                    {
                        selectCommand.Parameters.Add("@Route" + routeCounter, NpgsqlDbType.Varchar);
                        selectCommand.Parameters["@Route" + routeCounter].Value = route;
                        routeCounter++;
                    }
                }

                using (var reader = await selectCommand.ExecuteReaderAsync().ConfigureAwait(false))
                {
                    if (!reader.Read())
                    {
                        return(null);
                    }

                    //load up the message from the DB
                    long   id             = 0;
                    var    correlationId  = Guid.Empty;
                    byte[] headerPayload  = null;
                    byte[] messagePayload = null;

                    try
                    {
                        id             = (long)reader["queueid"];
                        correlationId  = (Guid)reader["CorrelationID"];
                        headerPayload  = (byte[])reader["Headers"];
                        messagePayload = (byte[])reader["body"];

                        var headers      = _serialization.InternalSerializer.ConvertBytesTo <IDictionary <string, object> >(headerPayload);
                        var messageGraph = (MessageInterceptorsGraph)headers[_headers.StandardHeaders.MessageInterceptorGraph.Name];
                        var message      = _serialization.Serializer.BytesToMessage <MessageBody>(messagePayload, messageGraph).Body;
                        var newMessage   = _messageFactory.Create(message, headers);

                        return(_receivedMessageFactory.Create(newMessage,
                                                              new MessageQueueId(id),
                                                              new MessageCorrelationId(correlationId)));
                    }
                    catch (Exception error)
                    {
                        //at this point, the record has been de-queued, but it can't be processed.
                        throw new PoisonMessageException(
                                  "An error has occurred trying to re-assemble a message de-queued from the server", error,
                                  new MessageQueueId(id), new MessageCorrelationId(correlationId),
                                  messagePayload, headerPayload);
                    }
                }
            }
        }