|
|
@@ -155,9 +155,10 @@ Result<QueryResult> StorageClient::query(const std::string& collection, const Qu
|
|
|
up.sortField = opts.sorts.front().first;
|
|
|
up.sortDescending = !opts.sorts.front().second;
|
|
|
}
|
|
|
- if (!opts.fields.empty()) {
|
|
|
- LOG_WARN("Storage: field projection not supported by upstream client; returning all fields");
|
|
|
- }
|
|
|
+ // Upstream has no server-side projection, so it is applied below once the
|
|
|
+ // documents are back. That still saves callers from serialising fields they
|
|
|
+ // never asked for, which is the difference between a summary listing and one
|
|
|
+ // carrying every node output.
|
|
|
up.limit = static_cast<uint32_t>(opts.page_size);
|
|
|
up.offset = static_cast<uint32_t>(std::max(0, (opts.page - 1) * opts.page_size));
|
|
|
|
|
|
@@ -166,6 +167,26 @@ Result<QueryResult> StorageClient::query(const std::string& collection, const Qu
|
|
|
out.documents = std::move(fr.documents);
|
|
|
out.total_count = static_cast<int64_t>(fr.totalCount);
|
|
|
out.has_more = fr.hasMore;
|
|
|
+
|
|
|
+ if (!opts.fields.empty()) {
|
|
|
+ for (auto& doc : out.documents) {
|
|
|
+ if (!doc.is_object()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ nlohmann::json projected = nlohmann::json::object();
|
|
|
+ for (auto it = doc.begin(); it != doc.end(); ++it) {
|
|
|
+ // Metadata keys are always kept: callers need the id and version
|
|
|
+ // regardless of which payload fields they asked for.
|
|
|
+ const bool is_metadata = !it.key().empty() && it.key().front() == '_';
|
|
|
+ if (is_metadata ||
|
|
|
+ std::find(opts.fields.begin(), opts.fields.end(), it.key()) != opts.fields.end()) {
|
|
|
+ projected[it.key()] = it.value();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ doc = std::move(projected);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return out;
|
|
|
}
|
|
|
|