async Task IBotDataStore <BotData> .SaveAsync(IAddress key, BotStoreType botStoreType, BotData botData,
                                                      CancellationToken cancellationToken)
        {
            try
            {
                var requestOptions = new RequestOptions()
                {
                    AccessCondition = new AccessCondition()
                    {
                        Type      = AccessConditionType.IfMatch,
                        Condition = botData.ETag
                    }
                };

                var entity    = new DocDbBotDataEntity(key, botStoreType, botData);
                var entityKey = DocDbBotDataEntity.GetEntityKey(key, botStoreType);

                if (string.IsNullOrEmpty(botData.ETag))
                {
                    await documentClient.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), entity, requestOptions);
                }
                else if (botData.ETag == "*")
                {
                    if (botData.Data != null)
                    {
                        await documentClient.UpsertDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), entity, requestOptions);
                    }
                    else
                    {
                        await documentClient.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, entityKey), requestOptions);
                    }
                }
                else
                {
                    if (botData.Data != null)
                    {
                        await documentClient.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, entityKey), entity, requestOptions);
                    }
                    else
                    {
                        await documentClient.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, entityKey), requestOptions);
                    }
                }
            }
            catch (DocumentClientException e)
            {
                //if (e.StatusCode.HasValue && e.StatusCode.Value == HttpStatusCode.Conflict)
                //{
                //    throw new HttpException((int)HttpStatusCode.PreconditionFailed, e.Message, e);
                //}

                //throw new HttpException(e.StatusCode.HasValue ? (int)e.StatusCode.Value : 0, e.Message, e);

                throw;
            }
        }
        async Task <BotData> IBotDataStore <BotData> .LoadAsync(IAddress key, BotStoreType botStoreType,
                                                                CancellationToken cancellationToken)
        {
            try
            {
                var entityKey = DocDbBotDataEntity.GetEntityKey(key, botStoreType);

                // query to retrieve the document if it exists
                SqlQuerySpec querySpec = new SqlQuerySpec(
                    queryText: $"SELECT * FROM {collectionId} b WHERE (b.id = {entityKeyParameterName})",
                    parameters: new SqlParameterCollection()
                {
                    new SqlParameter(entityKeyParameterName, entityKey)
                });
                var collectionUri = UriFactory.CreateDocumentCollectionUri(databaseId, collectionId);
                // execute the cross partition query if enableCrossPartitionQuery is true
                var feedOption = new FeedOptions {
                    EnableCrossPartitionQuery = enableCrossPartitionQuery
                };
                var query = documentClient.CreateDocumentQuery(collectionUri, querySpec, feedOption)
                            .AsDocumentQuery();
                var feedResponse = await query.ExecuteNextAsync <Document>(CancellationToken.None);

                Document document = feedResponse.FirstOrDefault();

                if (document != null)
                {
                    // The document, of type IDynamicMetaObjectProvider, has a dynamic nature,
                    // similar to DynamicTableEntity in Azure storage. When casting to a static type, properties that exist in the static type will be
                    // populated from the dynamic type.
                    DocDbBotDataEntity entity = (dynamic)document;
                    return(new BotData(document?.ETag, entity?.Data));
                }
                else
                {
                    // the document does not exist in the database, return an empty BotData object
                    return(new BotData(string.Empty, null));
                }
            }
            catch (DocumentClientException e)
            {
                if (e.StatusCode.HasValue && e.StatusCode.Value == HttpStatusCode.NotFound)
                {
                    return(new BotData(string.Empty, null));
                }

                //throw new HttpException(e.StatusCode.HasValue ? (int)e.StatusCode.Value : 0, e.Message, e);
                throw;
            }
        }