diff --git a/sdk/tables/assets.json b/sdk/tables/assets.json index 587fc753d2..c9b0f1d86e 100644 --- a/sdk/tables/assets.json +++ b/sdk/tables/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "cpp", "TagPrefix": "cpp/tables", - "Tag": "cpp/tables_ca30219607" + "Tag": "cpp/tables_69657814a3" } diff --git a/sdk/tables/azure-data-tables/inc/azure/data/tables/tables_clients.hpp b/sdk/tables/azure-data-tables/inc/azure/data/tables/tables_clients.hpp index 5329824e2e..8b74b9d987 100644 --- a/sdk/tables/azure-data-tables/inc/azure/data/tables/tables_clients.hpp +++ b/sdk/tables/azure-data-tables/inc/azure/data/tables/tables_clients.hpp @@ -301,6 +301,19 @@ namespace Azure { namespace Data { namespace Tables { Models::QueryEntitiesOptions const& options = {}, Core::Context const& context = {}); + /** + * @brief Get one table entity. + * + * @param partitionKey The partition key of the entity. + * @param rowKey The row key of the entity. + * @param context for canceling long running operations. + * @return Entity list paged response. + */ + Response GetEntity( + const std::string& partitionKey, + const std::string& rowKey, + Core::Context const& context = {}); + /** * @brief Creates a new transaction. * diff --git a/sdk/tables/azure-data-tables/src/tables_clients.cpp b/sdk/tables/azure-data-tables/src/tables_clients.cpp index 16263070f1..9f8e8605fe 100644 --- a/sdk/tables/azure-data-tables/src/tables_clients.cpp +++ b/sdk/tables/azure-data-tables/src/tables_clients.cpp @@ -672,8 +672,8 @@ Azure::Response TableClient::UpdateEntity( (void)options; auto url = m_url; url.AppendPath( - m_tableName + "(PartitionKey='" + tableEntity.PartitionKey + "',RowKey='" + tableEntity.RowKey - + "')"); + m_tableName + "(PartitionKey='" + Azure::Core::Url::Encode(tableEntity.PartitionKey) + + "',RowKey='" + Azure::Core::Url::Encode(tableEntity.RowKey) + "')"); std::string jsonBody = Serializers::UpdateEntity(tableEntity); @@ -716,8 +716,8 @@ Azure::Response TableClient::MergeEntity( (void)options; auto url = m_url; url.AppendPath( - m_tableName + "(PartitionKey='" + tableEntity.PartitionKey + "',RowKey='" + tableEntity.RowKey - + "')"); + m_tableName + "(PartitionKey='" + Azure::Core::Url::Encode(tableEntity.PartitionKey) + + "',RowKey='" + Azure::Core::Url::Encode(tableEntity.RowKey) + "')"); std::string jsonBody = Serializers::MergeEntity(tableEntity); @@ -758,8 +758,8 @@ Azure::Response TableClient::DeleteEntity( { auto url = m_url; url.AppendPath( - m_tableName + "(PartitionKey='" + tableEntity.PartitionKey + "',RowKey='" + tableEntity.RowKey - + "')"); + m_tableName + "(PartitionKey='" + Azure::Core::Url::Encode(tableEntity.PartitionKey) + + "',RowKey='" + Azure::Core::Url::Encode(tableEntity.RowKey) + "')"); Core::Http::Request request(Core::Http::HttpMethod::Delete, url); @@ -820,6 +820,39 @@ void Models::QueryEntitiesPagedResponse::OnNextPage(const Azure::Core::Context& *this = m_tableClient->QueryEntities(m_operationOptions, context); } +Azure::Response TableClient::GetEntity( + const std::string& partitionKey, + const std::string& rowKey, + Core::Context const& context) +{ + auto url = m_url; + url.AppendPath( + m_tableName + "(PartitionKey='" + Azure::Core::Url::Encode(partitionKey) + "',RowKey='" + + Azure::Core::Url::Encode(rowKey) + "')"); + + Core::Http::Request request(Core::Http::HttpMethod::Get, url); + request.SetHeader("Accept", "application/json;odata=fullmetadata"); + + auto rawResponse = m_pipeline->Send(request, context); + auto const httpStatusCode = rawResponse->GetStatusCode(); + if (httpStatusCode != Core::Http::HttpStatusCode::Ok) + { + throw Core::RequestFailedException(rawResponse); + } + + Models::TableEntity response{}; + { + const auto& responseBody = rawResponse->GetBody(); + std::string responseString = std::string(responseBody.begin(), responseBody.end()); + + auto const jsonRoot + = Azure::Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end()); + + response = Serializers::DeserializeEntity(jsonRoot); + } + return Response(std::move(response), std::move(rawResponse)); +} + Models::QueryEntitiesPagedResponse TableClient::QueryEntities( Models::QueryEntitiesOptions const& options, Core::Context const& context) @@ -828,11 +861,11 @@ Models::QueryEntitiesPagedResponse TableClient::QueryEntities( std::string appendPath = m_tableName + "("; if (!options.PartitionKey.empty()) { - appendPath += "PartitionKey='" + options.PartitionKey + "'"; + appendPath += "PartitionKey='" + Azure::Core::Url::Encode(options.PartitionKey) + "'"; } if (!options.RowKey.empty()) { - appendPath += ",RowKey='" + options.RowKey + "'"; + appendPath += ",RowKey='" + Azure::Core::Url::Encode(options.RowKey) + "'"; } appendPath += ")"; @@ -840,11 +873,11 @@ Models::QueryEntitiesPagedResponse TableClient::QueryEntities( if (options.Filter.HasValue()) { - url.AppendQueryParameter("$filter", options.Filter.Value()); + url.AppendQueryParameter("$filter", Azure::Core::Url::Encode(options.Filter.Value())); } if (!options.SelectColumns.empty()) { - url.AppendQueryParameter("$select", options.SelectColumns); + url.AppendQueryParameter("$select", Azure::Core::Url::Encode(options.SelectColumns)); } Core::Http::Request request(Core::Http::HttpMethod::Get, url); diff --git a/sdk/tables/azure-data-tables/test/ut/table_client_test.cpp b/sdk/tables/azure-data-tables/test/ut/table_client_test.cpp index e22f5b891c..32561c3b9d 100644 --- a/sdk/tables/azure-data-tables/test/ut/table_client_test.cpp +++ b/sdk/tables/azure-data-tables/test/ut/table_client_test.cpp @@ -469,6 +469,41 @@ namespace Azure { namespace Data { namespace Test { EXPECT_EQ(responseQuery.TableEntities.size(), 1); } + TEST_P(TablesClientTest, EntityGet) + { + if (GetParam() == AuthType::Key) + { + EXPECT_TRUE(true); + return; + } + Azure::Data::Tables::Models::TableEntity entity; + + entity.PartitionKey = "P1"; + entity.RowKey = "R1"; + entity.Properties["Name"] = "Azure"; + entity.Properties["Product"] = "Tables"; + auto createResponse = m_tableServiceClient->CreateTable(m_tableName); + auto response = m_tableClient->CreateEntity(entity); + EXPECT_EQ(response.RawResponse->GetStatusCode(), Azure::Core::Http::HttpStatusCode::NoContent); + EXPECT_FALSE(response.Value.ETag.empty()); + + entity.Properties["Product"] = "Tables2"; + entity.RowKey = "R2"; + m_tableClient->CreateEntity(entity); + + entity.Properties["Product"] = "Tables3"; + entity.RowKey = "R3"; + m_tableClient->CreateEntity(entity); + + std::string partitionKey = "P1"; + std::string rowKey = "R1"; + auto responseQuery = m_tableClient->GetEntity(partitionKey, rowKey); + EXPECT_EQ(responseQuery.Value.PartitionKey, "P1"); + EXPECT_EQ(responseQuery.Value.RowKey, "R1"); + EXPECT_EQ(responseQuery.Value.Properties["Name"], "Azure"); + EXPECT_EQ(responseQuery.Value.Properties["Product"], "Tables"); + } + TEST_P(TablesClientTest, TransactionCreateFail_LIVEONLY_) { Azure::Data::Tables::Models::TableEntity entity;