Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright (C) 2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

#pragma once

#include <sstream>
#include <string>
#include <utility>

#include <olp/core/porting/optional.h>
#include <olp/core/thread/TaskScheduler.h>
#include <olp/dataservice/read/DataServiceReadApi.h>

namespace olp {
namespace dataservice {
namespace read {

/**
* @brief Encapsulates the fields required to request a plain data blob for
* the given catalog, layer, and key.
*
* You must specify the key of the blob to be retrieved. If the key is not
* set in the request, the request fails with the following error:
* `ErrorCode::InvalidArgument`.
*/
class DATASERVICE_READ_API KeyDataRequest final {
public:
/**
* @brief Gets the key of the requested data blob.
*
* @return The key.
*/
const porting::optional<std::string>& GetKey() const { return key_; }

/**
* @brief Sets the key of the data blob to be retrieved.
*
* If the key cannot be found in the layer, the callback returns with an
* empty response (the `null` result for data and an error).
*
* @param key The key.
*
* @return A reference to the updated `KeyDataRequest` instance.
*/
template <class T = porting::optional<std::string>>
KeyDataRequest& WithKey(T&& key) {
key_ = std::forward<T>(key);
return *this;
}

/**
* @brief Gets the billing tag to group billing records together.
*
* The billing tag is an optional free-form tag that is used for grouping
* billing records together. If supplied, it must be 4–16 characters
* long and contain only alphanumeric ASCII characters [A-Za-z0-9].
*
* @return The `BillingTag` string or `olp::porting::none` if the billing tag
* is not set.
*/
const porting::optional<std::string>& GetBillingTag() const {
return billing_tag_;
}

/**
* @brief Sets the billing tag for the request.
*
* @see `GetBillingTag()` for information on usage and format.
*
* @param tag The `BillingTag` string or `olp::porting::none`.
*
* @return A reference to the updated `KeyDataRequest` instance.
*/
template <class T = porting::optional<std::string>>
KeyDataRequest& WithBillingTag(T&& tag) {
billing_tag_ = std::forward<T>(tag);
return *this;
}

/**
* @brief Gets the request priority.
*
* The default priority is `Priority::NORMAL`.
*
* @return The request priority.
*/
uint32_t GetPriority() const { return priority_; }

/**
* @brief Sets the priority of the request.
*
* @param priority The priority of the request.
*
* @return A reference to the updated `KeyDataRequest` instance.
*/
KeyDataRequest& WithPriority(uint32_t priority) {
priority_ = priority;
return *this;
}

/**
* @brief Creates a readable format for the request.
*
* @param layer_id The ID of the layer that is used for the request.
*
* @return A string representation of the request.
*/
std::string CreateKey(const std::string& layer_id) const {
std::stringstream out;
out << layer_id << "[";
if (GetKey()) {
out << *GetKey();
}
out << "]";
if (GetBillingTag()) {
out << "$" << *GetBillingTag();
}
return out.str();
}

private:
porting::optional<std::string> key_;
porting::optional<std::string> billing_tag_;
uint32_t priority_{thread::NORMAL};
};

} // namespace read
} // namespace dataservice
} // namespace olp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 HERE Europe B.V.
* Copyright (C) 2019-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,9 +31,9 @@
#include <olp/core/porting/optional.h>
#include <olp/dataservice/read/DataRequest.h>
#include <olp/dataservice/read/DataServiceReadApi.h>
#include <olp/dataservice/read/KeyDataRequest.h>
#include <olp/dataservice/read/PartitionsRequest.h>
#include <olp/dataservice/read/PrefetchPartitionsRequest.h>
#include <olp/dataservice/read/PrefetchTileResult.h>
#include <olp/dataservice/read/PrefetchTilesRequest.h>
#include <olp/dataservice/read/TileRequest.h>
#include <olp/dataservice/read/Types.h>
Expand Down Expand Up @@ -187,6 +187,46 @@ class DATASERVICE_READ_API VersionedLayerClient final {
*/
client::CancellableFuture<DataResponse> GetData(DataRequest data_request);

/**
* @brief Fetches a plain data blob asynchronously using a key.
*
* If the specified key cannot be found in the layer, the callback is invoked
* with the empty `DataResponse` object (the `nullptr` result and an error).
* If the key is not set in the request, the callback is invoked with the
* following error: `ErrorCode::InvalidArgument`.
*
* @note The key-based data is not cached at the moment; every request
* results in a network call.
*
* @param request The `KeyDataRequest` instance that contains a complete set
* of request parameters.
* @param callback The `DataResponseCallback` object that is invoked if
* the `DataResult` object is available or an error is encountered.
*
* @return A token that can be used to cancel this request.
*/
client::CancellationToken GetDataByKey(KeyDataRequest request,
DataResponseCallback callback);

/**
* @brief Fetches a plain data blob asynchronously using a key.
*
* If the specified key cannot be found in the layer, the callback is invoked
* with the empty `DataResponse` object (the `nullptr` result and an error).
* If the key is not set in the request, the callback is invoked with the
* following error: `ErrorCode::InvalidArgument`.
*
* @note The key-based data is not cached at the moment; every request
* results in a network call.
*
* @param request The `KeyDataRequest` instance that contains a complete set
* of request parameters.
*
* @return `CancellableFuture` that contains the `DataResponse` instance
* or an error. You can also use `CancellableFuture` to cancel this request.
*/
client::CancellableFuture<DataResponse> GetDataByKey(KeyDataRequest request);

/**
* @brief Fetches data asynchronously using a TileKey.
*
Expand Down
12 changes: 11 additions & 1 deletion olp-cpp-sdk-dataservice-read/src/VersionedLayerClient.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 HERE Europe B.V.
* Copyright (C) 2019-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -56,6 +56,16 @@
return impl_->GetData(std::move(data_request));
}

client::CancellationToken VersionedLayerClient::GetDataByKey(

Check warning on line 59 in olp-cpp-sdk-dataservice-read/src/VersionedLayerClient.cpp

View check run for this annotation

Codecov / codecov/patch

olp-cpp-sdk-dataservice-read/src/VersionedLayerClient.cpp#L59

Added line #L59 was not covered by tests
KeyDataRequest request, DataResponseCallback callback) {
return impl_->GetDataByKey(std::move(request), std::move(callback));

Check warning on line 61 in olp-cpp-sdk-dataservice-read/src/VersionedLayerClient.cpp

View check run for this annotation

Codecov / codecov/patch

olp-cpp-sdk-dataservice-read/src/VersionedLayerClient.cpp#L61

Added line #L61 was not covered by tests
}

client::CancellableFuture<DataResponse> VersionedLayerClient::GetDataByKey(
KeyDataRequest request) {
return impl_->GetDataByKey(std::move(request));
}

client::CancellationToken VersionedLayerClient::GetPartitions(
PartitionsRequest partitions_request, PartitionsResponseCallback callback) {
return impl_->GetPartitions(std::move(partitions_request),
Expand Down
27 changes: 27 additions & 0 deletions olp-cpp-sdk-dataservice-read/src/VersionedLayerClientImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,33 @@ client::CancellableFuture<DataResponse> VersionedLayerClientImpl::GetData(
return {cancel_token, std::move(promise)};
}

client::CancellationToken VersionedLayerClientImpl::GetDataByKey(
KeyDataRequest request, DataResponseCallback callback) {
auto data_task =
[=](const client::CancellationContext& context) mutable -> DataResponse {
if (!request.GetKey()) {
return client::ApiError::InvalidArgument("Key is missing");
}

repository::DataRepository repository(catalog_, settings_, lookup_client_,
mutex_storage_);
return repository.GetBlobDataByKey(layer_id_, request, context);
};

return task_sink_.AddTask(std::move(data_task), std::move(callback),
request.GetPriority());
}

client::CancellableFuture<DataResponse> VersionedLayerClientImpl::GetDataByKey(
KeyDataRequest request) {
auto promise = std::make_shared<std::promise<DataResponse>>();
auto cancel_token =
GetDataByKey(std::move(request), [promise](DataResponse response) {
promise->set_value(std::move(response));
});
return {cancel_token, std::move(promise)};
}

client::CancellationToken VersionedLayerClientImpl::PrefetchPartitions(
PrefetchPartitionsRequest request,
PrefetchPartitionsResponseCallback callback,
Expand Down
9 changes: 8 additions & 1 deletion olp-cpp-sdk-dataservice-read/src/VersionedLayerClientImpl.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 HERE Europe B.V.
* Copyright (C) 2019-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,6 +30,7 @@
#include <olp/core/client/PendingRequests.h>
#include <olp/core/porting/optional.h>
#include <olp/dataservice/read/DataRequest.h>
#include <olp/dataservice/read/KeyDataRequest.h>
#include <olp/dataservice/read/PartitionsRequest.h>
#include <olp/dataservice/read/PrefetchPartitionsRequest.h>
#include <olp/dataservice/read/PrefetchTileResult.h>
Expand Down Expand Up @@ -66,6 +67,12 @@ class VersionedLayerClientImpl {
virtual client::CancellableFuture<DataResponse> GetData(
DataRequest data_request);

virtual client::CancellationToken GetDataByKey(KeyDataRequest request,
DataResponseCallback callback);

virtual client::CancellableFuture<DataResponse> GetDataByKey(
KeyDataRequest request);

virtual client::CancellationToken GetData(TileRequest request,
DataResponseCallback callback);

Expand Down
52 changes: 48 additions & 4 deletions olp-cpp-sdk-dataservice-read/src/generated/api/BlobApi.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 HERE Europe B.V.
* Copyright (C) 2019-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,10 +22,9 @@
#include <cstring>
#include <map>
#include <memory>
#include <mutex>
#include <unordered_map>

#include <olp/core/client/OlpClient.h>
#include <olp/core/utils/Url.h>

namespace olp {
namespace dataservice {
Expand Down Expand Up @@ -55,7 +54,7 @@ BlobApi::DataResponse BlobApi::GetBlob(

// In case we know the size in advance, we should pre-allocated a buffer.
const auto expected_size = partition.GetDataSize();
const auto kPartitionPreallocateLimit = 10 * 1024 * 1024;
constexpr auto kPartitionPreallocateLimit = 10 * 1024 * 1024;
if (expected_size && *expected_size > 0 &&
*expected_size < kPartitionPreallocateLimit) {
buffer.reserve(*expected_size);
Expand Down Expand Up @@ -84,6 +83,51 @@ BlobApi::DataResponse BlobApi::GetBlob(
return {std::make_shared<std::vector<unsigned char>>(std::move(buffer)),
api_response.GetNetworkStatistics()};
}

BlobApi::DataResponse BlobApi::GetBlobByKey(
const client::OlpClient& client, const std::string& layer_id,
const std::string& key, porting::optional<std::string> billing_tag,
porting::optional<std::string> range,
const client::CancellationContext& context) {
std::multimap<std::string, std::string> header_params;
header_params.emplace("Accept", "application/octet-stream");
if (range) {
header_params.emplace("Range", *range);
}

std::multimap<std::string, std::string> query_params;
if (billing_tag) {
query_params.emplace("billingTag", *billing_tag);
}

std::string metadata_uri =
"/layers/" + layer_id + "/keys/" + olp::utils::Url::Encode(key);

std::vector<unsigned char> buffer;

auto data_callback = [&](const std::uint8_t* data, const std::uint64_t offset,
const std::size_t length) {
if (!offset) {
buffer.clear();
}

const auto buffer_size = buffer.size();
buffer.resize(buffer_size + length);
std::memcpy(buffer.data() + buffer_size, data, length);
};

auto api_response =
client.CallApiStream(metadata_uri, "GET", query_params, header_params,
data_callback, nullptr, "", context);

if (api_response.GetStatus() != http::HttpStatusCode::OK) {
return {client::ApiError(api_response.GetStatus()),
api_response.GetNetworkStatistics()};
}

return {std::make_shared<std::vector<unsigned char>>(std::move(buffer)),
api_response.GetNetworkStatistics()};
}
} // namespace read
} // namespace dataservice
} // namespace olp
Loading
Loading