From 841d5dbb97c405916a8f67fe841bf679389f4d76 Mon Sep 17 00:00:00 2001 From: viambot <79611529+viambot@users.noreply.github.com> Date: Wed, 13 May 2026 17:45:32 +0000 Subject: [PATCH] [WORKFLOW] AI update based on proto changes from commit 0afb2791e36ffb21e486f9c16ab77728b1e25bcc --- src/viam/sdk/app/data_client.cpp | 95 +++++++++++++++++++++- src/viam/sdk/app/data_client.hpp | 64 ++++++++++++++- src/viam/sdk/common/proto_value.cpp | 100 +++++++++++++++++++++++- src/viam/sdk/common/proto_value.hpp | 64 ++++++++++++++- src/viam/sdk/tests/test_proto_value.cpp | 73 ++++++++++++++++- 5 files changed, 391 insertions(+), 5 deletions(-) diff --git a/src/viam/sdk/app/data_client.cpp b/src/viam/sdk/app/data_client.cpp index 73bc8f9c8..5eed1cac5 100644 --- a/src/viam/sdk/app/data_client.cpp +++ b/src/viam/sdk/app/data_client.cpp @@ -98,5 +98,98 @@ std::vector DataClient::tabular_data_by_mql( const std::string& org_id, const std::vector& mql_binary) { return tabular_data_by_mql(org_id, mql_binary, tabular_data_by_mql_opts{}); } + +std::string DataClient::CreateSequence( + const std::string& part_id, + const std::vector& resources, + const std::vector& sequence_tags, + const boost::optional& start_time, + const boost::optional& end_time) { + return pimpl_->client_helper(&DataService::Stub::CreateSequence) + .with([&](app::data::v1::CreateSequenceRequest& req) { + req.set_part_id(part_id); + for (const auto& r : resources) { + *req.mutable_resources()->Add() = to_proto(r); + } + for (const auto& tag : sequence_tags) { + *req.mutable_sequence_tags()->Add() = tag; + } + if (start_time.has_value()) { + *req.mutable_start_time() = to_proto(*start_time); + } + if (end_time.has_value()) { + *req.mutable_end_time() = to_proto(*end_time); + } + }) + .invoke([](const app::data::v1::CreateSequenceResponse& resp) { return resp.id(); }); +} + +std::string DataClient::CreateSequence( + const std::string& part_id, + const std::vector& resources, + const std::vector& sequence_tags) { + return CreateSequence(part_id, resources, sequence_tags, boost::none, boost::none); +} + +DataClient::Sequence DataClient::GetSequence(const std::string& id) { + return pimpl_->client_helper(&DataService::Stub::GetSequence) + .with([&](app::data::v1::GetSequenceRequest& req) { req.set_id(id); }) + .invoke([](const app::data::v1::GetSequenceResponse& resp) { return from_proto(resp.sequence()); }); +} + +void DataClient::UpdateSequence(const std::string& id, const update_sequence_options& opts) { + return pimpl_->client_helper(&DataService::Stub::UpdateSequence) + .with([&](app::data::v1::UpdateSequenceRequest& req) { + req.set_id(id); + if (opts.resources.has_value()) { + for (const auto& r : *opts.resources) { + *req.mutable_resources()->Add() = to_proto(r); + } + } + if (opts.sequence_tags.has_value()) { + for (const auto& tag : *opts.sequence_tags) { + *req.mutable_sequence_tags()->Add() = tag; + } + } + if (opts.start_time.has_value()) { + *req.mutable_start_time() = to_proto(*opts.start_time); + } + if (opts.end_time.has_value()) { + *req.mutable_end_time() = to_proto(*opts.end_time); + } + for (const auto& path : opts.field_mask) { + *req.mutable_field_mask()->mutable_paths()->Add() = path; + } + }) + .invoke([](const app::data::v1::UpdateSequenceResponse& resp) {}); +} + +void DataClient::DeleteSequence(const std::string& id) { + return pimpl_->client_helper(&DataService::Stub::DeleteSequence) + .with([&](app::data::v1::DeleteSequenceRequest& req) { req.set_id(id); }) + .invoke([](const app::data::v1::DeleteSequenceResponse& resp) {}); +} + +std::pair, std::string> +DataClient::ListSequences(const std::string& organization_id, const list_sequences_options& opts) { + return pimpl_->client_helper(&DataService::Stub::ListSequences) + .with([&](app::data::v1::ListSequencesRequest& req) { + req.set_organization_id(organization_id); + if (opts.page_token.has_value()) { + req.set_page_token(*opts.page_token); + } + if (opts.page_size.has_value()) { + req.set_page_size(*opts.page_size); + } + }) + .invoke([](const app::data::v1::ListSequencesResponse& resp) { + return std::make_pair(from_repeated_field(resp.sequences()), resp.next_page_token()); + }); +} + +std::pair, std::string> +DataClient::ListSequences(const std::string& organization_id) { + return ListSequences(organization_id, list_sequences_options{}); +} } // namespace sdk -} // namespace viam +} // namespace viam \ No newline at end of file diff --git a/src/viam/sdk/app/data_client.hpp b/src/viam/sdk/app/data_client.hpp index 7f2031eab..572630dd8 100644 --- a/src/viam/sdk/app/data_client.hpp +++ b/src/viam/sdk/app/data_client.hpp @@ -29,6 +29,68 @@ class DataClient { boost::optional query_prefix; }; + struct SequenceResourceFilter { + std::string resource_name; + std::string method_name; + + bool operator==(const SequenceResourceFilter& other) const = default; + }; + + struct Sequence { + std::string id; + std::string part_id; + std::vector sequence_tags; + std::chrono::system_clock::time_point created_at; + std::chrono::system_clock::time_point updated_at; + std::chrono::system_clock::time_point start_time; + std::chrono::system_clock::time_point end_time; + std::vector resources; + + bool operator==(const Sequence& other) const = default; + }; + + struct update_sequence_options { + boost::optional> resources; + boost::optional> sequence_tags; + boost::optional start_time; + boost::optional end_time; + std::vector field_mask; + }; + + struct list_sequences_options { + boost::optional page_token; + boost::optional page_size; + }; + + // CreateSequence creates a new sequence. + std::string CreateSequence(const std::string& part_id, + const std::vector& resources, + const std::vector& sequence_tags, + const boost::optional& start_time, + const boost::optional& end_time); + + // Convenience overload with default options. + std::string CreateSequence(const std::string& part_id, + const std::vector& resources, + const std::vector& sequence_tags); + + // GetSequence retrieves a sequence by ID. + Sequence GetSequence(const std::string& id); + + // UpdateSequence updates the mutable fields of a sequence. + void UpdateSequence(const std::string& id, const update_sequence_options& opts); + + // DeleteSequence deletes a sequence by ID. + void DeleteSequence(const std::string& id); + + // ListSequences lists sequences for a given organization. + std::pair, std::string> ListSequences(const std::string& organization_id, + const list_sequences_options& opts); + + // Convenience overload with default options. + std::pair, std::string> ListSequences(const std::string& organization_id); + + using BSONBytes = std::vector; static DataClient from_viam_client(const ViamClient&); @@ -64,4 +126,4 @@ class DataClient { }; } // namespace sdk -} // namespace viam +} // namespace viam \ No newline at end of file diff --git a/src/viam/sdk/common/proto_value.cpp b/src/viam/sdk/common/proto_value.cpp index 16443b7f3..7e154eb6a 100644 --- a/src/viam/sdk/common/proto_value.cpp +++ b/src/viam/sdk/common/proto_value.cpp @@ -234,6 +234,44 @@ void to_value(const ProtoStruct& m, Value* v) { *(v->mutable_struct_value()) = to_proto(m); } +void to_value(const google::protobuf::FieldMask& fm, google::protobuf::Value* v) { + ProtoStruct s; + ProtoList paths_list; + for (const auto& path : fm.paths()) { + paths_list.push_back(path); + } + s.insert({"paths", paths_list}); + to_value(s, v); +} + +void to_value(const DataClient::SequenceResourceFilter& srf, google::protobuf::Value* v) { + ProtoStruct s; + s.insert({"resource_name", srf.resource_name}); + s.insert({"method_name", srf.method_name}); + to_value(s, v); +} + +void to_value(const DataClient::Sequence& seq, google::protobuf::Value* v) { + ProtoStruct s; + s.insert({"id", seq.id}); + s.insert({"part_id", seq.part_id}); + ProtoList tags_list; + for (const auto& tag : seq.sequence_tags) { + tags_list.push_back(tag); + } + s.insert({"sequence_tags", tags_list}); + s.insert({"created_at", to_proto(seq.created_at)}); + s.insert({"updated_at", to_proto(seq.updated_at)}); + s.insert({"start_time", to_proto(seq.start_time)}); + s.insert({"end_time", to_proto(seq.end_time)}); + ProtoList resources_list; + for (const auto& r : seq.resources) { + resources_list.push_back(r); + } + s.insert({"resources", resources_list}); + to_value(s, v); +} + } // namespace proto_value_details namespace proto_convert_details { @@ -293,7 +331,67 @@ ProtoStruct from_proto_impl::operator()( // NOLINT(mi return result; } +void to_proto_impl::operator()( + const DataClient::SequenceResourceFilter& srf, viam::app::data::v1::SequenceResourceFilter* p) const { + p->set_resource_name(srf.resource_name); + p->set_method_name(srf.method_name); +} + +DataClient::SequenceResourceFilter from_proto_impl::operator()( + const viam::app::data::v1::SequenceResourceFilter* p) const { + DataClient::SequenceResourceFilter srf; + srf.resource_name = p->resource_name(); + srf.method_name = p->method_name(); + return srf; +} + +void to_proto_impl::operator()( + const DataClient::Sequence& s, viam::app::data::v1::Sequence* p) const { + p->set_id(s.id); + p->set_part_id(s.part_id); + for (const auto& tag : s.sequence_tags) { + *p->mutable_sequence_tags()->Add() = tag; + } + *p->mutable_created_at() = to_proto(s.created_at); + *p->mutable_updated_at() = to_proto(s.updated_at); + *p->mutable_start_time() = to_proto(s.start_time); + *p->mutable_end_time() = to_proto(s.end_time); + for (const auto& r : s.resources) { + *p->mutable_resources()->Add() = to_proto(r); + } +} + +DataClient::Sequence from_proto_impl::operator()( + const viam::app::data::v1::Sequence* p) const { + DataClient::Sequence s; + s.id = p->id(); + s.part_id = p->part_id(); + s.sequence_tags = from_repeated_field(p->sequence_tags()); + s.created_at = from_proto(p->created_at()); + s.updated_at = from_proto(p->updated_at()); + s.start_time = from_proto(p->start_time()); + s.end_time = from_proto(p->end_time()); + s.resources = from_repeated_field(p->resources()); + return s; +} + +void to_proto_impl::operator()( + const google::protobuf::FieldMask& fm, google::protobuf::FieldMask* p) const { + for (const auto& path : fm.paths()) { + *p->mutable_paths()->Add() = path; + } +} + +google::protobuf::FieldMask from_proto_impl::operator()( + const google::protobuf::FieldMask* p) const { + google::protobuf::FieldMask fm; + for (const auto& path : p->paths()) { + *fm.mutable_paths()->Add() = path; + } + return fm; +} + } // namespace proto_convert_details } // namespace sdk -} // namespace viam +} // namespace viam \ No newline at end of file diff --git a/src/viam/sdk/common/proto_value.hpp b/src/viam/sdk/common/proto_value.hpp index 3c72d99e2..695efa088 100644 --- a/src/viam/sdk/common/proto_value.hpp +++ b/src/viam/sdk/common/proto_value.hpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace google { @@ -24,6 +25,10 @@ class Struct; namespace viam { namespace sdk { +// Forward declarations for new SDK types +class SequenceResourceFilter; +class Sequence; + namespace proto_value_details { struct move_may_throw { @@ -323,6 +328,39 @@ struct from_proto_impl { ProtoStruct operator()(const google::protobuf::Struct*) const; }; +// Specializations for SequenceResourceFilter +template <> +struct to_proto_impl { + void operator()(const SequenceResourceFilter&, viam::app::data::v1::SequenceResourceFilter*) const; +}; + +template <> +struct from_proto_impl { + SequenceResourceFilter operator()(const viam::app::data::v1::SequenceResourceFilter*) const; +}; + +// Specializations for Sequence +template <> +struct to_proto_impl { + void operator()(const Sequence&, viam::app::data::v1::Sequence*) const; +}; + +template <> +struct from_proto_impl { + Sequence operator()(const viam::app::data::v1::Sequence*) const; +}; + +// Specializations for google::protobuf::FieldMask +template <> +struct to_proto_impl { + void operator()(const google::protobuf::FieldMask&, google::protobuf::FieldMask*) const; +}; + +template <> +struct from_proto_impl { + google::protobuf::FieldMask operator()(const google::protobuf::FieldMask*) const; +}; + } // namespace proto_convert_details namespace proto_value_details { @@ -334,6 +372,13 @@ void to_value(std::string s, google::protobuf::Value* v); void to_value(const ProtoList& vec, google::protobuf::Value* v); void to_value(const ProtoStruct& m, google::protobuf::Value* v); +// Declaration for google::protobuf::FieldMask +void to_value(const google::protobuf::FieldMask& m, google::protobuf::Value* v); + +// Declarations for SequenceResourceFilter and Sequence +void to_value(const SequenceResourceFilter& srf, google::protobuf::Value* v); +void to_value(const Sequence& s, google::protobuf::Value* v); + template struct kind {}; @@ -370,6 +415,23 @@ struct kind { using type = KindConstant; }; +// Specialization for google::protobuf::FieldMask +template <> +struct kind { + using type = KindConstant; // FieldMask is a message, treated as struct +}; + +// Specializations for SequenceResourceFilter and Sequence +template <> +struct kind { + using type = KindConstant; +}; + +template <> +struct kind { + using type = KindConstant; +}; + } // namespace proto_value_details template @@ -396,4 +458,4 @@ T const* ProtoValue::get() const { } } // namespace sdk -} // namespace viam +} // namespace viam \ No newline at end of file diff --git a/src/viam/sdk/tests/test_proto_value.cpp b/src/viam/sdk/tests/test_proto_value.cpp index 5bd269ccf..e02e4e4ee 100644 --- a/src/viam/sdk/tests/test_proto_value.cpp +++ b/src/viam/sdk/tests/test_proto_value.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -332,7 +333,77 @@ BOOST_AUTO_TEST_CASE(test_manual_map_conversion) { }); } +BOOST_AUTO_TEST_CASE(test_sequence_resource_filter_conversion) { + DataClient::SequenceResourceFilter srf; + srf.resource_name = "test_resource"; + srf.method_name = "test_method"; + + ProtoValue pv_srf(srf); + BOOST_CHECK(pv_srf.is_a()); + BOOST_CHECK(pv_srf.get_unchecked() == srf); + + auto proto_srf = to_proto(srf); + BOOST_CHECK(proto_srf.resource_name() == srf.resource_name); + BOOST_CHECK(proto_srf.method_name() == srf.method_name); + + auto sdk_srf = from_proto(proto_srf); + BOOST_CHECK(sdk_srf == srf); +} + +BOOST_AUTO_TEST_CASE(test_sequence_conversion) { + DataClient::Sequence seq; + seq.id = "seq_id_1"; + seq.part_id = "part_id_1"; + seq.sequence_tags = {"tag1", "tag2"}; + seq.created_at = std::chrono::system_clock::now(); + seq.updated_at = seq.created_at; + seq.start_time = seq.created_at; + seq.end_time = seq.created_at + std::chrono::seconds(10); + + DataClient::SequenceResourceFilter srf1; + srf1.resource_name = "res1"; + srf1.method_name = "meth1"; + seq.resources.push_back(srf1); + + ProtoValue pv_seq(seq); + BOOST_CHECK(pv_seq.is_a()); + BOOST_CHECK(pv_seq.get_unchecked() == seq); + + auto proto_seq = to_proto(seq); + BOOST_CHECK(proto_seq.id() == seq.id); + BOOST_CHECK(proto_seq.part_id() == seq.part_id); + BOOST_CHECK(from_repeated_field(proto_seq.sequence_tags()) == seq.sequence_tags); + BOOST_CHECK(from_proto(proto_seq.created_at()) == seq.created_at); + BOOST_CHECK(from_proto(proto_seq.updated_at()) == seq.updated_at); + BOOST_CHECK(from_proto(proto_seq.start_time()) == seq.start_time); + BOOST_CHECK(from_proto(proto_seq.end_time()) == seq.end_time); + BOOST_CHECK(from_repeated_field(proto_seq.resources()) == seq.resources); + + auto sdk_seq = from_proto(proto_seq); + BOOST_CHECK(sdk_seq == seq); +} + +BOOST_AUTO_TEST_CASE(test_field_mask_conversion) { + google::protobuf::FieldMask fm; + fm.add_paths("path1"); + fm.add_paths("path2"); + + ProtoValue pv_fm(fm); + BOOST_CHECK(pv_fm.is_a()); + BOOST_CHECK(from_proto(pv_fm.get_unchecked()) == fm); + + auto proto_fm = to_proto(fm); + BOOST_CHECK(proto_fm.paths_size() == 2); + BOOST_CHECK(proto_fm.paths(0) == "path1"); + BOOST_CHECK(proto_fm.paths(1) == "path2"); + + auto sdk_fm = from_proto(proto_fm); + BOOST_CHECK(sdk_fm.paths_size() == 2); + BOOST_CHECK(sdk_fm.paths(0) == "path1"); + BOOST_CHECK(sdk_fm.paths(1) == "path2"); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace sdktests -} // namespace viam +} // namespace viam \ No newline at end of file