20 #include <unordered_set>
23 #include "graphar/status.h"
24 #include "mini-yaml/yaml/Yaml.hpp"
26 #include "graphar/filesystem.h"
27 #include "graphar/graph_info.h"
28 #include "graphar/result.h"
29 #include "graphar/types.h"
30 #include "graphar/version_parser.h"
31 #include "graphar/yaml.h"
35 #define CHECK_HAS_ADJ_LIST_TYPE(adj_list_type) \
37 if (!HasAdjacentListType(adj_list_type)) { \
38 return Status::KeyError( \
39 "Adjacency list type: ", AdjListTypeToString(adj_list_type), \
40 " is not found in edge info."); \
46 std::string ConcatEdgeTriple(
const std::string& src_type,
47 const std::string& edge_type,
48 const std::string& dst_type) {
49 return src_type + REGULAR_SEPARATOR + edge_type + REGULAR_SEPARATOR +
53 template <
int NotFoundValue = -1>
54 int LookupKeyIndex(
const std::unordered_map<std::string, int>& key_to_index,
55 const std::string& type) {
56 auto it = key_to_index.find(type);
57 if (it == key_to_index.end()) {
64 std::vector<T> AddVectorElement(
const std::vector<T>& values, T new_element) {
66 out.reserve(values.size() + 1);
67 for (
size_t i = 0; i < values.size(); ++i) {
68 out.push_back(values[i]);
70 out.emplace_back(std::move(new_element));
74 std::string BuildPath(
const std::vector<std::string>& paths) {
76 for (
const auto& p : paths) {
77 if (p.back() ==
'/') {
87 bool operator==(
const Property& lhs,
const Property& rhs) {
88 return (lhs.name == rhs.name) && (lhs.type == rhs.type) &&
89 (lhs.is_primary == rhs.is_primary) &&
90 (lhs.is_nullable == rhs.is_nullable) &&
91 (lhs.cardinality == rhs.cardinality);
95 FileType file_type,
const std::string& prefix)
96 : properties_(properties), file_type_(file_type), prefix_(prefix) {
97 if (prefix_.empty() && !properties_.empty()) {
98 for (
const auto& p : properties_) {
99 prefix_ += p.name + REGULAR_SEPARATOR;
101 prefix_.back() =
'/';
109 bool PropertyGroup::HasProperty(
const std::string& property_name)
const {
110 for (
const auto& p : properties_) {
111 if (p.name == property_name) {
119 if (prefix_.empty() ||
120 (file_type_ != FileType::CSV && file_type_ != FileType::PARQUET &&
121 file_type_ != FileType::ORC)) {
124 if (properties_.empty()) {
127 std::unordered_set<std::string> check_property_unique_set;
128 for (
const auto& p : properties_) {
129 if (p.name.empty() || p.type ==
nullptr) {
132 if (check_property_unique_set.find(p.name) !=
133 check_property_unique_set.end()) {
136 check_property_unique_set.insert(p.name);
139 if (p.type->id() == Type::LIST && file_type_ == FileType::CSV) {
144 if (p.cardinality != Cardinality::SINGLE && file_type_ == FileType::CSV) {
152 std::shared_ptr<PropertyGroup> CreatePropertyGroup(
153 const std::vector<Property>& properties, FileType file_type,
154 const std::string& prefix) {
155 if (properties.empty()) {
159 return std::make_shared<PropertyGroup>(properties, file_type, prefix);
162 bool operator==(
const PropertyGroup& lhs,
const PropertyGroup& rhs) {
163 return (lhs.GetPrefix() == rhs.GetPrefix()) &&
164 (lhs.GetFileType() == rhs.GetFileType()) &&
165 (lhs.GetProperties() == rhs.GetProperties());
169 const std::string& prefix)
170 : type_(type), file_type_(file_type), prefix_(prefix) {
171 if (prefix_.empty()) {
172 prefix_ = std::string(AdjListTypeToString(type_)) +
"/";
177 if (type_ != AdjListType::unordered_by_source &&
178 type_ != AdjListType::ordered_by_source &&
179 type_ != AdjListType::unordered_by_dest &&
180 type_ != AdjListType::ordered_by_dest) {
183 if (prefix_.empty() ||
184 (file_type_ != FileType::CSV && file_type_ != FileType::PARQUET &&
185 file_type_ != FileType::ORC)) {
191 std::shared_ptr<AdjacentList> CreateAdjacentList(AdjListType type,
193 const std::string& prefix) {
194 return std::make_shared<AdjacentList>(type, file_type, prefix);
199 Impl(
const std::string& type, IdType chunk_size,
const std::string& prefix,
200 const PropertyGroupVector& property_groups,
201 const std::vector<std::string>& labels,
202 std::shared_ptr<const InfoVersion>
version)
204 chunk_size_(chunk_size),
205 property_groups_(std::move(property_groups)),
209 if (prefix_.empty()) {
210 prefix_ = type_ +
"/";
212 for (
size_t i = 0; i < property_groups_.size(); i++) {
213 const auto& pg = property_groups_[i];
217 for (
const auto& p : pg->GetProperties()) {
218 property_name_to_index_.emplace(p.name, i);
219 property_name_to_primary_.emplace(p.name, p.is_primary);
220 property_name_to_nullable_.emplace(p.name, p.is_nullable);
221 property_name_to_type_.emplace(p.name, p.type);
222 property_name_to_cardinality_.emplace(p.name, p.cardinality);
227 bool is_validated()
const noexcept {
228 if (type_.empty() || chunk_size_ <= 0 || prefix_.empty()) {
231 std::unordered_set<std::string> check_property_unique_set;
232 for (
const auto& pg : property_groups_) {
234 if (!pg || !pg->IsValidated()) {
238 for (
const auto& p : pg->GetProperties()) {
239 if (check_property_unique_set.find(p.name) !=
240 check_property_unique_set.end()) {
243 check_property_unique_set.insert(p.name);
253 PropertyGroupVector property_groups_;
254 std::vector<std::string> labels_;
256 std::shared_ptr<const InfoVersion> version_;
257 std::unordered_map<std::string, int> property_name_to_index_;
258 std::unordered_map<std::string, bool> property_name_to_primary_;
259 std::unordered_map<std::string, bool> property_name_to_nullable_;
260 std::unordered_map<std::string, std::shared_ptr<DataType>>
261 property_name_to_type_;
262 std::unordered_map<std::string, Cardinality> property_name_to_cardinality_;
266 const PropertyGroupVector& property_groups,
267 const std::vector<std::string>& labels,
268 const std::string& prefix,
269 std::shared_ptr<const InfoVersion> version)
270 : impl_(new
Impl(type, chunk_size, prefix, property_groups, labels,
273 VertexInfo::~VertexInfo() =
default;
282 return impl_->labels_;
286 return impl_->version_;
290 std::shared_ptr<PropertyGroup> property_group, IdType chunk_index)
const {
291 if (property_group ==
nullptr) {
294 return BuildPath({impl_->prefix_, property_group->GetPrefix()}) +
"chunk" +
295 std::to_string(chunk_index);
299 std::shared_ptr<PropertyGroup> property_group)
const {
300 if (property_group ==
nullptr) {
303 return BuildPath({impl_->prefix_, property_group->GetPrefix()});
307 return BuildPath({impl_->prefix_}) +
"vertex_count";
311 return static_cast<int>(impl_->property_groups_.size());
315 const std::string& property_name)
const {
316 int i = LookupKeyIndex(impl_->property_name_to_index_, property_name);
317 return i == -1 ? nullptr : impl_->property_groups_[i];
322 if (index < 0 || index >=
static_cast<int>(impl_->property_groups_.size())) {
325 return impl_->property_groups_[index];
329 return impl_->property_groups_;
333 auto it = impl_->property_name_to_primary_.find(property_name);
334 if (it == impl_->property_name_to_primary_.end()) {
341 auto it = impl_->property_name_to_nullable_.find(property_name);
342 if (it == impl_->property_name_to_nullable_.end()) {
349 return impl_->property_name_to_index_.find(property_name) !=
350 impl_->property_name_to_index_.end();
354 const std::shared_ptr<PropertyGroup>& property_group)
const {
355 if (property_group ==
nullptr) {
358 for (
const auto& pg : impl_->property_groups_) {
359 if (*pg == *property_group) {
367 const std::string& property_name)
const {
368 auto it = impl_->property_name_to_type_.find(property_name);
369 if (it == impl_->property_name_to_type_.end()) {
375 Result<Cardinality> VertexInfo::GetPropertyCardinality(
376 const std::string& property_name)
const {
377 auto it = impl_->property_name_to_cardinality_.find(property_name);
378 if (it == impl_->property_name_to_cardinality_.end()) {
385 std::shared_ptr<PropertyGroup> property_group)
const {
386 if (property_group ==
nullptr) {
389 for (
const auto& property : property_group->GetProperties()) {
391 return Status::Invalid(
"property in the property group already exists: ",
395 return std::make_shared<VertexInfo>(
396 impl_->type_, impl_->chunk_size_,
397 AddVectorElement(impl_->property_groups_, property_group), impl_->labels_,
398 impl_->prefix_, impl_->version_);
403 std::shared_ptr<VertexInfo> CreateVertexInfo(
404 const std::string& type, IdType chunk_size,
405 const PropertyGroupVector& property_groups,
406 const std::vector<std::string>& labels,
const std::string& prefix,
407 std::shared_ptr<const InfoVersion> version) {
408 if (type.empty() || chunk_size <= 0) {
411 return std::make_shared<VertexInfo>(type, chunk_size, property_groups, labels,
416 std::shared_ptr<Yaml> yaml) {
417 if (yaml ==
nullptr) {
420 std::string type = yaml->operator[](
"type").As<std::string>();
422 static_cast<IdType
>(yaml->operator[](
"chunk_size").As<int64_t>());
424 if (!yaml->operator[](
"prefix").IsNone()) {
425 prefix = yaml->operator[](
"prefix").As<std::string>();
427 std::vector<std::string> labels;
428 const auto& labels_node = yaml->operator[](
"labels");
429 if (labels_node.IsSequence()) {
430 for (
auto it = labels_node.Begin(); it != labels_node.End(); it++) {
431 labels.push_back((*it).second.As<std::string>());
434 std::shared_ptr<const InfoVersion>
version =
nullptr;
435 if (!yaml->operator[](
"version").IsNone()) {
440 PropertyGroupVector property_groups;
441 auto property_groups_node = yaml->operator[](
"property_groups");
442 if (!property_groups_node.IsNone()) {
443 for (
auto it = property_groups_node.Begin();
444 it != property_groups_node.End(); it++) {
445 std::string pg_prefix;
446 auto& node = (*it).second;
447 if (!node[
"prefix"].IsNone()) {
448 pg_prefix = node[
"prefix"].As<std::string>();
450 auto file_type = StringToFileType(node[
"file_type"].As<std::string>());
451 std::vector<Property> property_vec;
452 auto& properties = node[
"properties"];
453 for (
auto iit = properties.Begin(); iit != properties.End(); iit++) {
454 auto& p_node = (*iit).second;
455 auto property_name = p_node[
"name"].As<std::string>();
457 DataType::TypeNameToDataType(p_node[
"data_type"].As<std::string>());
458 bool is_primary = p_node[
"is_primary"].As<
bool>();
460 p_node[
"is_nullable"].IsNone() || p_node[
"is_nullable"].As<
bool>();
461 Cardinality cardinality = Cardinality::SINGLE;
462 if (!p_node[
"cardinality"].IsNone()) {
464 StringToCardinality(p_node[
"cardinality"].As<std::string>());
466 property_vec.emplace_back(property_name, property_type, is_primary,
467 is_nullable, cardinality);
469 property_groups.push_back(
470 std::make_shared<PropertyGroup>(property_vec, file_type, pg_prefix));
473 return std::make_shared<VertexInfo>(type, chunk_size, property_groups, labels,
478 GAR_ASSIGN_OR_RAISE(
auto yaml,
Yaml::Load(input));
486 std::string dump_string;
489 node[
"type"] = impl_->type_;
490 node[
"chunk_size"] = std::to_string(impl_->chunk_size_);
491 node[
"prefix"] = impl_->prefix_;
492 if (impl_->labels_.size() > 0) {
494 for (
const auto& label : impl_->labels_) {
495 node[
"labels"].PushBack();
496 node[
"labels"][node[
"labels"].Size() - 1] = label;
499 for (
const auto& pg : impl_->property_groups_) {
500 ::Yaml::Node pg_node;
501 if (!pg->GetPrefix().empty()) {
502 pg_node[
"prefix"] = pg->GetPrefix();
504 pg_node[
"file_type"] = FileTypeToString(pg->GetFileType());
505 for (
const auto& p : pg->GetProperties()) {
507 p_node[
"name"] = p.name;
508 p_node[
"data_type"] = p.type->ToTypeName();
509 p_node[
"is_primary"] = p.is_primary ?
"true" :
"false";
510 p_node[
"is_nullable"] = p.is_nullable ?
"true" :
"false";
511 if (p.cardinality != Cardinality::SINGLE) {
512 p_node[
"cardinality"] = CardinalityToString(p.cardinality);
514 pg_node[
"properties"].PushBack();
515 pg_node[
"properties"][pg_node[
"properties"].Size() - 1] = p_node;
517 node[
"property_groups"].PushBack();
518 node[
"property_groups"][node[
"property_groups"].Size() - 1] = pg_node;
520 if (impl_->version_ !=
nullptr) {
521 node[
"version"] = impl_->version_->ToString();
523 ::Yaml::Serialize(node, dump_string);
524 }
catch (
const std::exception& e) {
531 std::string no_url_path;
532 GAR_ASSIGN_OR_RAISE(
auto fs, FileSystemFromUriOrPath(path, &no_url_path));
533 GAR_ASSIGN_OR_RAISE(
auto yaml_content, this->
Dump());
534 return fs->WriteValueToFile(yaml_content, no_url_path);
539 Impl(
const std::string& src_type,
const std::string& edge_type,
540 const std::string& dst_type, IdType chunk_size, IdType src_chunk_size,
541 IdType dst_chunk_size,
bool directed,
const std::string& prefix,
542 const AdjacentListVector& adjacent_lists,
543 const PropertyGroupVector& property_groups,
544 std::shared_ptr<const InfoVersion>
version)
545 : src_type_(src_type),
546 edge_type_(edge_type),
548 chunk_size_(chunk_size),
549 src_chunk_size_(src_chunk_size),
550 dst_chunk_size_(dst_chunk_size),
553 adjacent_lists_(std::move(adjacent_lists)),
554 property_groups_(std::move(property_groups)),
556 if (prefix_.empty()) {
557 prefix_ = src_type_ + REGULAR_SEPARATOR + edge_type_ + REGULAR_SEPARATOR +
560 for (
size_t i = 0; i < adjacent_lists_.size(); i++) {
561 if (!adjacent_lists_[i]) {
565 auto adj_list_type = adjacent_lists_[i]->GetType();
566 adjacent_list_type_to_index_[adj_list_type] = i;
568 for (
size_t i = 0; i < property_groups_.size(); i++) {
569 const auto& pg = property_groups_[i];
573 for (
const auto& p : pg->GetProperties()) {
574 property_name_to_index_.emplace(p.name, i);
575 property_name_to_primary_.emplace(p.name, p.is_primary);
576 property_name_to_nullable_.emplace(p.name, p.is_nullable);
577 property_name_to_type_.emplace(p.name, p.type);
582 bool is_validated()
const noexcept {
583 if (src_type_.empty() || edge_type_.empty() || dst_type_.empty() ||
584 chunk_size_ <= 0 || src_chunk_size_ <= 0 || dst_chunk_size_ <= 0 ||
585 prefix_.empty() || adjacent_lists_.empty()) {
589 for (
const auto& al : adjacent_lists_) {
590 if (!al || !al->IsValidated()) {
595 std::unordered_set<std::string> check_property_unique_set;
596 for (
const auto& pg : property_groups_) {
598 if (!pg || !pg->IsValidated()) {
602 for (
const auto& p : pg->GetProperties()) {
603 if (p.cardinality != Cardinality::SINGLE) {
606 <<
"Edge property only supports single cardinality, but got: "
607 << CardinalityToString(p.cardinality) << std::endl;
610 if (check_property_unique_set.find(p.name) !=
611 check_property_unique_set.end()) {
614 check_property_unique_set.insert(p.name);
618 if (adjacent_lists_.size() != adjacent_list_type_to_index_.size()) {
624 std::string src_type_;
625 std::string edge_type_;
626 std::string dst_type_;
628 IdType src_chunk_size_;
629 IdType dst_chunk_size_;
632 AdjacentListVector adjacent_lists_;
633 PropertyGroupVector property_groups_;
634 std::unordered_map<AdjListType, int> adjacent_list_type_to_index_;
635 std::unordered_map<std::string, int> property_name_to_index_;
636 std::unordered_map<std::string, bool> property_name_to_primary_;
637 std::unordered_map<std::string, bool> property_name_to_nullable_;
638 std::unordered_map<std::string, std::shared_ptr<DataType>>
639 property_name_to_type_;
640 std::shared_ptr<const InfoVersion> version_;
644 const std::string& dst_type, IdType chunk_size,
645 IdType src_chunk_size, IdType dst_chunk_size,
bool directed,
646 const AdjacentListVector& adjacent_lists,
647 const PropertyGroupVector& property_groups,
648 const std::string& prefix,
649 std::shared_ptr<const InfoVersion> version)
650 : impl_(new
Impl(src_type, edge_type, dst_type, chunk_size, src_chunk_size,
651 dst_chunk_size, directed, prefix, adjacent_lists,
652 property_groups, version)) {}
654 EdgeInfo::~EdgeInfo() =
default;
673 return impl_->version_;
677 return impl_->adjacent_list_type_to_index_.find(adj_list_type) !=
678 impl_->adjacent_list_type_to_index_.end();
682 return impl_->property_name_to_index_.find(property_name) !=
683 impl_->property_name_to_index_.end();
687 const std::shared_ptr<PropertyGroup>& property_group)
const {
688 if (property_group ==
nullptr) {
691 for (
const auto& pg : impl_->property_groups_) {
692 if (*pg == *property_group) {
699 std::shared_ptr<AdjacentList> EdgeInfo::GetAdjacentList(
700 AdjListType adj_list_type)
const {
701 auto it = impl_->adjacent_list_type_to_index_.find(adj_list_type);
702 if (it == impl_->adjacent_list_type_to_index_.end()) {
705 return impl_->adjacent_lists_[it->second];
709 return static_cast<int>(impl_->property_groups_.size());
713 return impl_->property_groups_;
717 const std::string& property_name)
const {
718 int i = LookupKeyIndex(impl_->property_name_to_index_, property_name);
719 return i == -1 ? nullptr : impl_->property_groups_[i];
724 if (index < 0 || index >=
static_cast<int>(impl_->property_groups_.size())) {
727 return impl_->property_groups_[index];
731 AdjListType adj_list_type)
const {
732 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
733 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
734 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix()}) +
739 IdType vertex_chunk_index, AdjListType adj_list_type)
const {
740 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
741 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
742 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix()}) +
743 "edge_count" + std::to_string(vertex_chunk_index);
747 IdType vertex_chunk_index, IdType edge_chunk_index,
748 AdjListType adj_list_type)
const {
749 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
750 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
751 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix()}) +
752 "adj_list/part" + std::to_string(vertex_chunk_index) +
"/chunk" +
753 std::to_string(edge_chunk_index);
757 AdjListType adj_list_type)
const {
758 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
759 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
760 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix()}) +
765 IdType vertex_chunk_index, AdjListType adj_list_type)
const {
766 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
767 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
768 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix()}) +
769 "offset/chunk" + std::to_string(vertex_chunk_index);
773 AdjListType adj_list_type)
const {
774 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
775 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
776 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix()}) +
781 const std::shared_ptr<PropertyGroup>& property_group,
782 AdjListType adj_list_type, IdType vertex_chunk_index,
783 IdType edge_chunk_index)
const {
784 if (property_group ==
nullptr) {
787 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
788 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
789 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix(),
790 property_group->GetPrefix()}) +
791 "part" + std::to_string(vertex_chunk_index) +
"/chunk" +
792 std::to_string(edge_chunk_index);
796 const std::shared_ptr<PropertyGroup>& property_group,
797 AdjListType adj_list_type)
const {
798 if (property_group ==
nullptr) {
801 CHECK_HAS_ADJ_LIST_TYPE(adj_list_type);
802 int i = impl_->adjacent_list_type_to_index_.at(adj_list_type);
803 return BuildPath({impl_->prefix_, impl_->adjacent_lists_[i]->GetPrefix(),
804 property_group->GetPrefix()});
808 const std::string& property_name)
const {
809 auto it = impl_->property_name_to_type_.find(property_name);
810 if (it == impl_->property_name_to_type_.end()) {
817 auto it = impl_->property_name_to_primary_.find(property_name);
818 if (it == impl_->property_name_to_primary_.end()) {
825 auto it = impl_->property_name_to_nullable_.find(property_name);
826 if (it == impl_->property_name_to_nullable_.end()) {
833 std::shared_ptr<AdjacentList> adj_list)
const {
834 if (adj_list ==
nullptr) {
839 AdjListTypeToString(adj_list->GetType()));
841 return std::make_shared<EdgeInfo>(
842 impl_->src_type_, impl_->edge_type_, impl_->dst_type_, impl_->chunk_size_,
843 impl_->src_chunk_size_, impl_->dst_chunk_size_, impl_->directed_,
844 AddVectorElement(impl_->adjacent_lists_, adj_list),
845 impl_->property_groups_, impl_->prefix_, impl_->version_);
849 std::shared_ptr<PropertyGroup> property_group)
const {
850 if (property_group ==
nullptr) {
853 for (
const auto& property : property_group->GetProperties()) {
859 return std::make_shared<EdgeInfo>(
860 impl_->src_type_, impl_->edge_type_, impl_->dst_type_, impl_->chunk_size_,
861 impl_->src_chunk_size_, impl_->dst_chunk_size_, impl_->directed_,
862 impl_->adjacent_lists_,
863 AddVectorElement(impl_->property_groups_, property_group), impl_->prefix_,
869 std::shared_ptr<EdgeInfo> CreateEdgeInfo(
870 const std::string& src_type,
const std::string& edge_type,
871 const std::string& dst_type, IdType chunk_size, IdType src_chunk_size,
872 IdType dst_chunk_size,
bool directed,
873 const AdjacentListVector& adjacent_lists,
874 const PropertyGroupVector& property_groups,
const std::string& prefix,
875 std::shared_ptr<const InfoVersion> version) {
876 if (src_type.empty() || edge_type.empty() || dst_type.empty() ||
877 chunk_size <= 0 || src_chunk_size <= 0 || dst_chunk_size <= 0 ||
878 adjacent_lists.empty()) {
881 return std::make_shared<EdgeInfo>(
882 src_type, edge_type, dst_type, chunk_size, src_chunk_size, dst_chunk_size,
883 directed, adjacent_lists, property_groups, prefix, version);
887 if (yaml ==
nullptr) {
890 std::string src_type = yaml->operator[](
"src_type").As<std::string>();
891 std::string edge_type = yaml->operator[](
"edge_type").As<std::string>();
892 std::string dst_type = yaml->operator[](
"dst_type").As<std::string>();
894 static_cast<IdType
>(yaml->operator[](
"chunk_size").As<int64_t>());
895 IdType src_chunk_size =
896 static_cast<IdType
>(yaml->operator[](
"src_chunk_size").As<int64_t>());
897 IdType dst_chunk_size =
898 static_cast<IdType
>(yaml->operator[](
"dst_chunk_size").As<int64_t>());
899 bool directed = yaml->operator[](
"directed").As<bool>();
901 if (!yaml->operator[](
"prefix").IsNone()) {
902 prefix = yaml->operator[](
"prefix").As<std::string>();
904 std::shared_ptr<const InfoVersion>
version =
nullptr;
905 if (!yaml->operator[](
"version").IsNone()) {
911 AdjacentListVector adjacent_lists;
912 PropertyGroupVector property_groups;
913 auto adj_lists_node = yaml->operator[](
"adj_lists");
914 if (adj_lists_node.IsSequence()) {
915 for (
auto it = adj_lists_node.Begin(); it != adj_lists_node.End(); it++) {
916 auto& node = (*it).second;
917 auto ordered = node[
"ordered"].As<
bool>();
918 auto aligned = node[
"aligned_by"].As<std::string>();
919 auto adj_list_type = OrderedAlignedToAdjListType(ordered, aligned);
920 auto file_type = StringToFileType(node[
"file_type"].As<std::string>());
921 std::string adj_list_prefix;
922 if (!node[
"prefix"].IsNone()) {
923 adj_list_prefix = node[
"prefix"].As<std::string>();
925 adjacent_lists.push_back(std::make_shared<AdjacentList>(
926 adj_list_type, file_type, adj_list_prefix));
929 auto property_groups_node = yaml->operator[](
"property_groups");
930 if (!property_groups_node.IsNone()) {
931 for (
auto pg_it = property_groups_node.Begin();
932 pg_it != property_groups_node.End(); pg_it++) {
933 auto& pg_node = (*pg_it).second;
934 std::string pg_prefix;
935 if (!pg_node[
"prefix"].IsNone()) {
936 pg_prefix = pg_node[
"prefix"].As<std::string>();
938 auto file_type = StringToFileType(pg_node[
"file_type"].As<std::string>());
939 auto properties = pg_node[
"properties"];
940 std::vector<Property> property_vec;
941 for (
auto p_it = properties.Begin(); p_it != properties.End(); p_it++) {
942 auto& p_node = (*p_it).second;
943 auto property_name = p_node[
"name"].As<std::string>();
945 DataType::TypeNameToDataType(p_node[
"data_type"].As<std::string>());
946 if (!p_node[
"cardinality"].IsNone() &&
947 StringToCardinality(p_node[
"cardinality"].As<std::string>()) !=
948 Cardinality::SINGLE) {
950 "Unsupported set cardinality for edge property.");
952 bool is_primary = p_node[
"is_primary"].As<
bool>();
954 p_node[
"is_nullable"].IsNone() || p_node[
"is_nullable"].As<
bool>();
955 property_vec.emplace_back(property_name, property_type, is_primary,
958 property_groups.push_back(
959 std::make_shared<PropertyGroup>(property_vec, file_type, pg_prefix));
962 return std::make_shared<EdgeInfo>(
963 src_type, edge_type, dst_type, chunk_size, src_chunk_size, dst_chunk_size,
964 directed, adjacent_lists, property_groups, prefix,
version);
968 GAR_ASSIGN_OR_RAISE(
auto yaml,
Yaml::Load(input));
976 std::string dump_string;
979 node[
"src_type"] = impl_->src_type_;
980 node[
"edge_type"] = impl_->edge_type_;
981 node[
"dst_type"] = impl_->dst_type_;
982 node[
"chunk_size"] = std::to_string(impl_->chunk_size_);
983 node[
"src_chunk_size"] = std::to_string(impl_->src_chunk_size_);
984 node[
"dst_chunk_size"] = std::to_string(impl_->dst_chunk_size_);
985 node[
"prefix"] = impl_->prefix_;
986 node[
"directed"] = impl_->directed_ ?
"true" :
"false";
987 for (
const auto& adjacent_list : impl_->adjacent_lists_) {
988 ::Yaml::Node adj_list_node;
989 auto adj_list_type = adjacent_list->GetType();
990 auto pair = AdjListTypeToOrderedAligned(adj_list_type);
991 adj_list_node[
"ordered"] = pair.first ?
"true" :
"false";
992 adj_list_node[
"aligned_by"] = pair.second;
993 adj_list_node[
"prefix"] = adjacent_list->GetPrefix();
994 adj_list_node[
"file_type"] =
995 FileTypeToString(adjacent_list->GetFileType());
996 node[
"adj_lists"].PushBack();
997 node[
"adj_lists"][node[
"adj_lists"].Size() - 1] = adj_list_node;
999 for (
const auto& pg : impl_->property_groups_) {
1000 ::Yaml::Node pg_node;
1001 if (!pg->GetPrefix().empty()) {
1002 pg_node[
"prefix"] = pg->GetPrefix();
1004 pg_node[
"file_type"] = FileTypeToString(pg->GetFileType());
1005 for (
const auto& p : pg->GetProperties()) {
1006 ::Yaml::Node p_node;
1007 p_node[
"name"] = p.name;
1008 p_node[
"data_type"] = p.type->ToTypeName();
1009 p_node[
"is_primary"] = p.is_primary ?
"true" :
"false";
1010 p_node[
"is_nullable"] = p.is_nullable ?
"true" :
"false";
1011 pg_node[
"properties"].PushBack();
1012 pg_node[
"properties"][pg_node[
"properties"].Size() - 1] = p_node;
1014 node[
"property_groups"].PushBack();
1015 node[
"property_groups"][node[
"property_groups"].Size() - 1] = pg_node;
1017 if (impl_->version_ !=
nullptr) {
1018 node[
"version"] = impl_->version_->ToString();
1020 ::Yaml::Serialize(node, dump_string);
1021 }
catch (
const std::exception& e) {
1028 std::string no_url_path;
1029 GAR_ASSIGN_OR_RAISE(
auto fs, FileSystemFromUriOrPath(path, &no_url_path));
1030 GAR_ASSIGN_OR_RAISE(
auto yaml_content, this->
Dump());
1031 return fs->WriteValueToFile(yaml_content, no_url_path);
1036 static std::string PathToDirectory(
const std::string& path) {
1037 if (path.rfind(
"s3://", 0) == 0) {
1038 int t = path.find_last_of(
'?');
1039 std::string prefix = path.substr(0, t);
1040 std::string suffix = path.substr(t);
1041 const size_t last_slash_idx = prefix.rfind(
'/');
1042 if (std::string::npos != last_slash_idx) {
1043 return prefix.substr(0, last_slash_idx + 1) + suffix;
1046 const size_t last_slash_idx = path.rfind(
'/');
1047 if (std::string::npos != last_slash_idx) {
1048 return path.substr(0, last_slash_idx + 1);
1054 static Result<std::shared_ptr<GraphInfo>> ConstructGraphInfo(
1055 std::shared_ptr<Yaml> graph_meta,
const std::string& default_name,
1056 const std::string& default_prefix,
const std::shared_ptr<FileSystem> fs,
1057 const std::string& no_url_path) {
1058 std::string name = default_name;
1059 std::string prefix = default_prefix;
1060 if (!graph_meta->operator[](
"name").IsNone()) {
1061 name = graph_meta->operator[](
"name").As<std::string>();
1063 if (!graph_meta->operator[](
"prefix").IsNone()) {
1064 prefix = graph_meta->operator[](
"prefix").As<std::string>();
1066 std::shared_ptr<const InfoVersion> version =
nullptr;
1067 if (!graph_meta->operator[](
"version").IsNone()) {
1068 GAR_ASSIGN_OR_RAISE(
1070 graph_meta->operator[](
"version").As<std::string>()));
1072 std::unordered_map<std::string, std::string> extra_info;
1073 if (!graph_meta->operator[](
"extra_info").IsNone()) {
1074 auto& extra_info_node = graph_meta->operator[](
"extra_info");
1075 for (
auto it = extra_info_node.Begin(); it != extra_info_node.End(); it++) {
1076 auto node = (*it).second;
1077 auto key = node[
"key"].As<std::string>();
1078 auto value = node[
"value"].As<std::string>();
1079 extra_info.emplace(key, value);
1083 VertexInfoVector vertex_infos;
1084 EdgeInfoVector edge_infos;
1085 const auto& vertices = graph_meta->operator[](
"vertices");
1086 if (vertices.IsSequence()) {
1087 for (
auto it = vertices.Begin(); it != vertices.End(); it++) {
1088 std::string vertex_meta_file =
1089 no_url_path + (*it).second.As<std::string>();
1090 GAR_ASSIGN_OR_RAISE(
auto input,
1091 fs->ReadFileToValue<std::string>(vertex_meta_file));
1092 GAR_ASSIGN_OR_RAISE(
auto vertex_meta,
Yaml::Load(input));
1094 vertex_infos.push_back(vertex_info);
1097 const auto& edges = graph_meta->operator[](
"edges");
1098 if (edges.IsSequence()) {
1099 for (
auto it = edges.Begin(); it != edges.End(); it++) {
1100 std::string edge_meta_file = no_url_path + (*it).second.As<std::string>();
1101 GAR_ASSIGN_OR_RAISE(
auto input,
1102 fs->ReadFileToValue<std::string>(edge_meta_file));
1103 GAR_ASSIGN_OR_RAISE(
auto edge_meta,
Yaml::Load(input));
1105 edge_infos.push_back(edge_info);
1109 std::vector<std::string> labels;
1110 if (!graph_meta->operator[](
"labels").IsNone()) {
1111 const auto& labels_node = graph_meta->operator[](
"labels");
1112 if (labels_node.IsSequence()) {
1113 for (
auto it = labels_node.Begin(); it != labels_node.End(); it++) {
1114 labels.push_back((*it).second.As<std::string>());
1118 return std::make_shared<GraphInfo>(name, vertex_infos, edge_infos, labels,
1119 prefix, version, extra_info);
1126 Impl(
const std::string& graph_name, VertexInfoVector vertex_infos,
1127 EdgeInfoVector edge_infos,
const std::vector<std::string>& labels,
1128 const std::string& prefix, std::shared_ptr<const InfoVersion>
version,
1129 const std::unordered_map<std::string, std::string>& extra_info)
1130 : name_(graph_name),
1131 vertex_infos_(std::move(vertex_infos)),
1132 edge_infos_(std::move(edge_infos)),
1136 extra_info_(extra_info) {
1137 for (
size_t i = 0; i < vertex_infos_.size(); i++) {
1138 if (vertex_infos_[i] !=
nullptr) {
1139 vtype_to_index_[vertex_infos_[i]->GetType()] = i;
1142 for (
size_t i = 0; i < edge_infos_.size(); i++) {
1143 if (edge_infos_[i] !=
nullptr) {
1144 std::string edge_key = ConcatEdgeTriple(edge_infos_[i]->GetSrcType(),
1145 edge_infos_[i]->GetEdgeType(),
1146 edge_infos_[i]->GetDstType());
1147 etype_to_index_[edge_key] = i;
1152 bool is_validated()
const noexcept {
1153 if (name_.empty() || prefix_.empty()) {
1156 for (
const auto& v : vertex_infos_) {
1157 if (!v || !v->IsValidated()) {
1161 for (
const auto& e : edge_infos_) {
1162 if (!e || !e->IsValidated()) {
1166 if (vertex_infos_.size() != vtype_to_index_.size() ||
1167 edge_infos_.size() != etype_to_index_.size()) {
1174 VertexInfoVector vertex_infos_;
1175 EdgeInfoVector edge_infos_;
1176 std::vector<std::string> labels_;
1177 std::string prefix_;
1178 std::shared_ptr<const InfoVersion> version_;
1179 std::unordered_map<std::string, std::string> extra_info_;
1180 std::unordered_map<std::string, int> vtype_to_index_;
1181 std::unordered_map<std::string, int> etype_to_index_;
1185 const std::string& graph_name, VertexInfoVector vertex_infos,
1186 EdgeInfoVector edge_infos,
const std::vector<std::string>& labels,
1187 const std::string& prefix, std::shared_ptr<const InfoVersion> version,
1188 const std::unordered_map<std::string, std::string>& extra_info)
1189 : impl_(new
Impl(graph_name, std::move(vertex_infos), std::move(edge_infos),
1190 labels, prefix, version, extra_info)) {}
1192 GraphInfo::~GraphInfo() =
default;
1197 return impl_->labels_;
1203 return impl_->version_;
1208 return impl_->extra_info_;
1212 const std::string& type)
const {
1214 return i == -1 ? nullptr : impl_->vertex_infos_[i];
1218 return LookupKeyIndex(impl_->vtype_to_index_, type);
1222 const std::string& src_type,
const std::string& edge_type,
1223 const std::string& dst_type)
const {
1225 return i == -1 ? nullptr : impl_->edge_infos_[i];
1229 const std::string& edge_type,
1230 const std::string& dst_type)
const {
1231 std::string edge_key = ConcatEdgeTriple(src_type, edge_type, dst_type);
1232 return LookupKeyIndex(impl_->etype_to_index_, edge_key);
1236 return static_cast<int>(impl_->vertex_infos_.size());
1240 return static_cast<int>(impl_->edge_infos_.size());
1245 if (index < 0 || index >=
static_cast<int>(impl_->vertex_infos_.size())) {
1248 return impl_->vertex_infos_[index];
1252 if (index < 0 || index >=
static_cast<int>(impl_->edge_infos_.size())) {
1255 return impl_->edge_infos_[index];
1259 return impl_->vertex_infos_;
1263 return impl_->edge_infos_;
1269 std::shared_ptr<VertexInfo> vertex_info)
const {
1270 if (vertex_info ==
nullptr) {
1276 return std::make_shared<GraphInfo>(
1277 impl_->name_, AddVectorElement(impl_->vertex_infos_, vertex_info),
1278 impl_->edge_infos_, impl_->labels_, impl_->prefix_, impl_->version_);
1282 std::shared_ptr<EdgeInfo> edge_info)
const {
1283 if (edge_info ==
nullptr) {
1287 edge_info->GetDstType()) != -1) {
1290 return std::make_shared<GraphInfo>(
1291 impl_->name_, impl_->vertex_infos_,
1292 AddVectorElement(impl_->edge_infos_, edge_info), impl_->labels_,
1293 impl_->prefix_, impl_->version_);
1296 std::shared_ptr<GraphInfo> CreateGraphInfo(
1297 const std::string& name,
const VertexInfoVector& vertex_infos,
1298 const EdgeInfoVector& edge_infos,
const std::vector<std::string>& labels,
1299 const std::string& prefix, std::shared_ptr<const InfoVersion> version,
1300 const std::unordered_map<std::string, std::string>& extra_info) {
1304 return std::make_shared<GraphInfo>(name, vertex_infos, edge_infos, labels,
1305 prefix, version, extra_info);
1309 std::string no_url_path;
1310 GAR_ASSIGN_OR_RAISE(
auto fs, FileSystemFromUriOrPath(path, &no_url_path));
1311 GAR_ASSIGN_OR_RAISE(
auto yaml_content,
1312 fs->ReadFileToValue<std::string>(no_url_path));
1313 GAR_ASSIGN_OR_RAISE(
auto graph_meta,
Yaml::Load(yaml_content));
1314 std::string default_name =
"graph";
1315 std::string default_prefix = PathToDirectory(path);
1316 no_url_path = PathToDirectory(no_url_path);
1317 return ConstructGraphInfo(graph_meta, default_name, default_prefix, fs,
1322 const std::string& input,
const std::string& relative_location) {
1323 GAR_ASSIGN_OR_RAISE(
auto graph_meta,
Yaml::Load(input));
1324 std::string default_name =
"graph";
1325 std::string default_prefix =
1327 std::string no_url_path;
1328 GAR_ASSIGN_OR_RAISE(
auto fs,
1329 FileSystemFromUriOrPath(relative_location, &no_url_path));
1330 return ConstructGraphInfo(graph_meta, default_name, default_prefix, fs,
1339 std::string dump_string;
1341 node[
"name"] = impl_->name_;
1342 node[
"prefix"] = impl_->prefix_;
1346 node[
"vertices"].PushBack();
1347 node[
"vertices"][node[
"vertices"].Size() - 1] =
1348 vertex->GetType() +
".vertex.yaml";
1351 node[
"edges"].PushBack();
1352 node[
"edges"][node[
"edges"].Size() - 1] =
1353 ConcatEdgeTriple(edge->GetSrcType(), edge->GetEdgeType(),
1354 edge->GetDstType()) +
1357 if (impl_->labels_.size() > 0) {
1359 for (
const auto& label : impl_->labels_) {
1360 node[
"labels"].PushBack();
1361 node[
"labels"][node[
"labels"].Size() - 1] = label;
1364 if (impl_->version_ !=
nullptr) {
1365 node[
"version"] = impl_->version_->ToString();
1367 if (impl_->extra_info_.size() > 0) {
1369 for (
const auto& pair : impl_->extra_info_) {
1370 ::Yaml::Node extra_info_node;
1371 extra_info_node[
"key"] = pair.first;
1372 extra_info_node[
"value"] = pair.second;
1373 node[
"extra_info"].PushBack();
1374 node[
"extra_info"][node[
"extra_info"].Size() - 1] = extra_info_node;
1377 ::Yaml::Serialize(node, dump_string);
1378 }
catch (
const std::exception& e) {
1385 std::string no_url_path;
1386 GAR_ASSIGN_OR_RAISE(
auto fs, FileSystemFromUriOrPath(path, &no_url_path));
1387 GAR_ASSIGN_OR_RAISE(
auto yaml_content, this->
Dump());
1388 return fs->WriteValueToFile(yaml_content, no_url_path);
AdjacentList(AdjListType type, FileType file_type, const std::string &prefix="")
const std::string & GetEdgeType() const
static Result< std::shared_ptr< EdgeInfo > > Load(std::shared_ptr< Yaml > yaml)
Result< std::string > GetAdjListFilePath(IdType vertex_chunk_index, IdType edge_chunk_index, AdjListType adj_list_type) const
Get the file path of adj list topology chunk.
Status Save(const std::string &file_name) const
Result< std::shared_ptr< DataType > > GetPropertyType(const std::string &property_name) const
const std::string & GetPrefix() const
Result< std::string > GetEdgesNumFilePath(IdType vertex_chunk_index, AdjListType adj_list_type) const
Result< std::string > GetPropertyGroupPathPrefix(const std::shared_ptr< PropertyGroup > &property_group, AdjListType adj_list_type) const
bool IsPrimaryKey(const std::string &property_name) const
Result< std::string > GetAdjListOffsetFilePath(IdType vertex_chunk_index, AdjListType adj_list_type) const
Get the adjacency list offset chunk file path of vertex chunk the offset chunks is aligned with the v...
IdType GetChunkSize() const
bool HasProperty(const std::string &property_name) const
Returns whether the edge info contains the given property.
Result< std::shared_ptr< EdgeInfo > > AddAdjacentList(std::shared_ptr< AdjacentList > adj_list) const
Result< std::string > Dump() const noexcept
bool IsNullableKey(const std::string &property_name) const
std::shared_ptr< PropertyGroup > GetPropertyGroupByIndex(int index) const
Get the property group at the specified index.
bool HasPropertyGroup(const std::shared_ptr< PropertyGroup > &property_group) const
Returns whether the edge info contains the given property group.
const std::shared_ptr< const InfoVersion > & version() const
Result< std::shared_ptr< EdgeInfo > > AddPropertyGroup(std::shared_ptr< PropertyGroup > property_group) const
const std::string & GetSrcType() const
bool HasAdjacentListType(AdjListType adj_list_type) const
Result< std::string > GetOffsetPathPrefix(AdjListType adj_list_type) const
Result< std::string > GetAdjListPathPrefix(AdjListType adj_list_type) const
Get the path prefix of the adjacency list topology chunk for the given adjacency list type.
EdgeInfo(const std::string &src_type, const std::string &edge_type, const std::string &dst_type, IdType chunk_size, IdType src_chunk_size, IdType dst_chunk_size, bool directed, const AdjacentListVector &adjacent_lists, const PropertyGroupVector &property_groups, const std::string &prefix="", std::shared_ptr< const InfoVersion > version=nullptr)
Construct an EdgeInfo object with the given information and property groups.
IdType GetDstChunkSize() const
Result< std::string > GetPropertyFilePath(const std::shared_ptr< PropertyGroup > &property_group, AdjListType adj_list_type, IdType vertex_chunk_index, IdType edge_chunk_index) const
Get the chunk file path of adj list property group the property group chunks is aligned with the adj ...
const std::string & GetDstType() const
IdType GetSrcChunkSize() const
const PropertyGroupVector & GetPropertyGroups() const
Get the property groups.
Result< std::string > GetVerticesNumFilePath(AdjListType adj_list_type) const
Get the file path for the number of vertices.
std::shared_ptr< PropertyGroup > GetPropertyGroup(const std::string &property) const
Get the property group containing the given property.
int PropertyGroupNum() const
Get the number of property groups.
int GetVertexInfoIndex(const std::string &type) const
Get the vertex info index with the given type.
const EdgeInfoVector & GetEdgeInfos() const
Get the edge infos of graph info.
GraphInfo(const std::string &graph_name, VertexInfoVector vertex_infos, EdgeInfoVector edge_infos, const std::vector< std::string > &labels={}, const std::string &prefix="./", std::shared_ptr< const InfoVersion > version=nullptr, const std::unordered_map< std::string, std::string > &extra_info={})
Constructs a GraphInfo instance.
Status Save(const std::string &path) const
const std::shared_ptr< VertexInfo > GetVertexInfoByIndex(int index) const
Get the vertex info at the specified index.
Result< std::shared_ptr< GraphInfo > > AddVertex(std::shared_ptr< VertexInfo > vertex_info) const
Adds a vertex info to the GraphInfo instance and returns a new GraphInfo.
const std::string & GetPrefix() const
Get the absolute path prefix of the chunk files.
static Result< std::shared_ptr< GraphInfo > > Load(const std::string &path)
Loads the input file as a GraphInfo instance.
Result< std::string > Dump() const
std::shared_ptr< EdgeInfo > GetEdgeInfo(const std::string &src_type, const std::string &edge_type, const std::string &dst_type) const
Get the edge info with the given source vertex type, edge type, and destination vertex type.
int EdgeInfoNum() const
Get the number of edge infos.
std::shared_ptr< VertexInfo > GetVertexInfo(const std::string &type) const
Get the vertex info with the given type.
const std::vector< std::string > & GetLabels() const
Get the vertex labels of the graph.
Result< std::shared_ptr< GraphInfo > > AddEdge(std::shared_ptr< EdgeInfo > edge_info) const
Adds an edge info to the GraphInfo instance and returns a new GraphInfo.
const VertexInfoVector & GetVertexInfos() const
Get the vertex infos of graph info.
const std::unordered_map< std::string, std::string > & GetExtraInfo() const
Get the extra metadata of the graph info object.
int GetEdgeInfoIndex(const std::string &src_type, const std::string &edge_type, const std::string &dst_type) const
Get the edge info index with the given source vertex type, edge type, and destination type.
int VertexInfoNum() const
Get the number of vertex infos.
const std::string & GetName() const
Get the name of the graph.
const std::shared_ptr< const InfoVersion > & version() const
Get the version info of the graph info object.
const std::shared_ptr< EdgeInfo > GetEdgeInfoByIndex(int index) const
Get the edge info at the specified index.
static Result< std::shared_ptr< const InfoVersion > > Parse(const std::string &str) noexcept
PropertyGroup(const std::vector< Property > &properties, FileType file_type, const std::string &prefix="")
const std::vector< Property > & GetProperties() const
Status outcome object (success or error)
static Status YamlError(Args &&... args)
static Status Invalid(Args &&... args)
const std::string & GetType() const
std::shared_ptr< PropertyGroup > GetPropertyGroup(const std::string &property_name) const
Result< std::string > GetPathPrefix(std::shared_ptr< PropertyGroup > property_group) const
const std::vector< std::string > & GetLabels() const
IdType GetChunkSize() const
const std::shared_ptr< const InfoVersion > & version() const
Result< std::shared_ptr< VertexInfo > > AddPropertyGroup(std::shared_ptr< PropertyGroup > property_group) const
bool HasProperty(const std::string &property_name) const
bool HasPropertyGroup(const std::shared_ptr< PropertyGroup > &property_group) const
Result< std::string > GetFilePath(std::shared_ptr< PropertyGroup > property_group, IdType chunk_index) const
bool IsPrimaryKey(const std::string &property_name) const
int PropertyGroupNum() const
const std::string & GetPrefix() const
Result< std::string > GetVerticesNumFilePath() const
Result< std::shared_ptr< DataType > > GetPropertyType(const std::string &property_name) const
VertexInfo(const std::string &type, IdType chunk_size, const PropertyGroupVector &property_groups, const std::vector< std::string > &labels={}, const std::string &prefix="", std::shared_ptr< const InfoVersion > version=nullptr)
bool IsNullableKey(const std::string &property_name) const
Result< std::string > Dump() const noexcept
static Result< std::shared_ptr< VertexInfo > > Load(std::shared_ptr< Yaml > yaml)
std::shared_ptr< PropertyGroup > GetPropertyGroupByIndex(int index) const
Status Save(const std::string &file_name) const
const PropertyGroupVector & GetPropertyGroups() const
static Result< std::shared_ptr< Yaml > > Load(const std::string &input)