|
|
@@ -628,6 +628,138 @@ public:
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ // ===== View Management =====
|
|
|
+
|
|
|
+ bool createView(const std::string& name,
|
|
|
+ const std::string& collection,
|
|
|
+ const std::vector<std::string>& include,
|
|
|
+ const std::vector<std::string>& exclude,
|
|
|
+ const std::vector<Client::Filter>& where,
|
|
|
+ const std::optional<Client::Sort>& defaultSort) {
|
|
|
+ smartbotic::databasepb::CreateViewRequest request;
|
|
|
+ request.set_name(name);
|
|
|
+ request.set_collection(collection);
|
|
|
+ for (const auto& p : include) request.add_include(p);
|
|
|
+ for (const auto& p : exclude) request.add_exclude(p);
|
|
|
+
|
|
|
+ for (const auto& f : where) {
|
|
|
+ auto* pb = request.add_where();
|
|
|
+ pb->set_field(f.field);
|
|
|
+ pb->set_op(static_cast<smartbotic::databasepb::FilterOp>(f.op));
|
|
|
+ pb->set_value(f.value.dump());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (defaultSort) {
|
|
|
+ auto* s = request.mutable_default_sort();
|
|
|
+ s->set_field(defaultSort->field);
|
|
|
+ s->set_descending(defaultSort->descending);
|
|
|
+ }
|
|
|
+
|
|
|
+ smartbotic::databasepb::CreateViewResponse response;
|
|
|
+ grpc::ClientContext context;
|
|
|
+ setDeadline(context);
|
|
|
+
|
|
|
+ auto status = stub_->CreateView(&context, request, &response);
|
|
|
+ if (!status.ok()) {
|
|
|
+ spdlog::error("Client::createView failed: {}", status.error_message());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!response.success()) {
|
|
|
+ spdlog::error("Client::createView rejected: {}", response.error());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool dropView(const std::string& name) {
|
|
|
+ smartbotic::databasepb::DropViewRequest request;
|
|
|
+ request.set_name(name);
|
|
|
+ smartbotic::databasepb::DropViewResponse response;
|
|
|
+ grpc::ClientContext context;
|
|
|
+ setDeadline(context);
|
|
|
+
|
|
|
+ auto status = stub_->DropView(&context, request, &response);
|
|
|
+ if (!status.ok()) {
|
|
|
+ spdlog::error("Client::dropView failed: {}", status.error_message());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return response.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<Client::ViewDefinition> listViews() {
|
|
|
+ smartbotic::databasepb::ListViewsRequest request;
|
|
|
+ smartbotic::databasepb::ListViewsResponse response;
|
|
|
+ grpc::ClientContext context;
|
|
|
+ setDeadline(context);
|
|
|
+
|
|
|
+ std::vector<Client::ViewDefinition> out;
|
|
|
+ auto status = stub_->ListViews(&context, request, &response);
|
|
|
+ if (!status.ok()) {
|
|
|
+ spdlog::error("Client::listViews failed: {}", status.error_message());
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+ for (const auto& pb : response.views()) {
|
|
|
+ Client::ViewDefinition v;
|
|
|
+ v.name = pb.name();
|
|
|
+ v.collection = pb.collection();
|
|
|
+ for (const auto& p : pb.include()) v.include.push_back(p);
|
|
|
+ for (const auto& p : pb.exclude()) v.exclude.push_back(p);
|
|
|
+ for (const auto& pbf : pb.where()) {
|
|
|
+ Client::Filter f;
|
|
|
+ f.field = pbf.field();
|
|
|
+ f.op = static_cast<Client::FilterOp>(pbf.op());
|
|
|
+ try { f.value = nlohmann::json::parse(pbf.value()); }
|
|
|
+ catch (...) { f.value = pbf.value(); }
|
|
|
+ v.where.push_back(f);
|
|
|
+ }
|
|
|
+ if (pb.has_default_sort()) {
|
|
|
+ Client::Sort s;
|
|
|
+ s.field = pb.default_sort().field();
|
|
|
+ s.descending = pb.default_sort().descending();
|
|
|
+ v.defaultSort = s;
|
|
|
+ }
|
|
|
+ v.createdAt = pb.created_at();
|
|
|
+ v.updatedAt = pb.updated_at();
|
|
|
+ out.push_back(std::move(v));
|
|
|
+ }
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::optional<Client::ViewDefinition> getViewInfo(const std::string& name) {
|
|
|
+ smartbotic::databasepb::GetViewInfoRequest request;
|
|
|
+ request.set_name(name);
|
|
|
+ smartbotic::databasepb::GetViewInfoResponse response;
|
|
|
+ grpc::ClientContext context;
|
|
|
+ setDeadline(context);
|
|
|
+
|
|
|
+ auto status = stub_->GetViewInfo(&context, request, &response);
|
|
|
+ if (!status.ok() || !response.found()) {
|
|
|
+ return std::nullopt;
|
|
|
+ }
|
|
|
+ Client::ViewDefinition v;
|
|
|
+ v.name = response.view().name();
|
|
|
+ v.collection = response.view().collection();
|
|
|
+ for (const auto& p : response.view().include()) v.include.push_back(p);
|
|
|
+ for (const auto& p : response.view().exclude()) v.exclude.push_back(p);
|
|
|
+ for (const auto& pbf : response.view().where()) {
|
|
|
+ Client::Filter f;
|
|
|
+ f.field = pbf.field();
|
|
|
+ f.op = static_cast<Client::FilterOp>(pbf.op());
|
|
|
+ try { f.value = nlohmann::json::parse(pbf.value()); }
|
|
|
+ catch (...) { f.value = pbf.value(); }
|
|
|
+ v.where.push_back(f);
|
|
|
+ }
|
|
|
+ if (response.view().has_default_sort()) {
|
|
|
+ Client::Sort s;
|
|
|
+ s.field = response.view().default_sort().field();
|
|
|
+ s.descending = response.view().default_sort().descending();
|
|
|
+ v.defaultSort = s;
|
|
|
+ }
|
|
|
+ v.createdAt = response.view().created_at();
|
|
|
+ v.updatedAt = response.view().updated_at();
|
|
|
+ return v;
|
|
|
+ }
|
|
|
+
|
|
|
// ===== Event Subscription =====
|
|
|
|
|
|
class SubscriptionHandle {
|
|
|
@@ -1234,6 +1366,27 @@ std::optional<Client::CollectionInfo> Client::getCollectionInfo(const std::strin
|
|
|
return impl_->getCollectionInfo(name);
|
|
|
}
|
|
|
|
|
|
+bool Client::createView(const std::string& name,
|
|
|
+ const std::string& collection,
|
|
|
+ const std::vector<std::string>& include,
|
|
|
+ const std::vector<std::string>& exclude,
|
|
|
+ const std::vector<Filter>& where,
|
|
|
+ const std::optional<Sort>& defaultSort) {
|
|
|
+ return impl_->createView(name, collection, include, exclude, where, defaultSort);
|
|
|
+}
|
|
|
+
|
|
|
+bool Client::dropView(const std::string& name) {
|
|
|
+ return impl_->dropView(name);
|
|
|
+}
|
|
|
+
|
|
|
+std::vector<Client::ViewDefinition> Client::listViews() {
|
|
|
+ return impl_->listViews();
|
|
|
+}
|
|
|
+
|
|
|
+std::optional<Client::ViewDefinition> Client::getViewInfo(const std::string& name) {
|
|
|
+ return impl_->getViewInfo(name);
|
|
|
+}
|
|
|
+
|
|
|
std::shared_ptr<void> Client::subscribe(const std::vector<std::string>& collections, EventCallback callback) {
|
|
|
return impl_->subscribe(collections, std::move(callback));
|
|
|
}
|