AnnaDB 1.0
Loading...
Searching...
No Matches
TySON.hpp
1//
2// Created by felix on 29.01.23.
3//
4
5#ifndef ANNADB_DRIVER_TYSON_HPP
6#define ANNADB_DRIVER_TYSON_HPP
7
8#include <algorithm>
9#include <ranges>
10#include <string_view>
11#include "utils.hpp"
12
13namespace tyson
14{
18 enum class TySonType
19 {
20 Number,
21 String,
22 Bool,
23 Null,
24 Timestamp,
25 Link,
26 Vector,
27 Map,
28 Object,
29 ID,
30 Objects,
31 IDs,
32 Value,
33 ProjectValue,
34 Keep,
35 };
36
42 template<std::convertible_to<TySonType> Obj>
43 std::string_view TySonType_repr(Obj &&obj) noexcept
44 {
45 switch (obj)
46 {
47 case TySonType::Number:
48 return "TySON-Number";
49 case TySonType::String:
50 return "TySON-String";
51 case TySonType::Bool:
52 return "TySON-Bool";
53 case TySonType::Null:
54 return "TySON-Null";
55 case TySonType::Timestamp:
56 return "TySON-Timestamp";
57 case TySonType::Link:
58 return "TySON-Link";
59 case TySonType::Vector:
60 return "TySON-Vector";
61 case TySonType::Map:
62 return "TySON-Map";
63 case TySonType::Object:
64 return "TySON-Object";
65 case TySonType::ID:
66 return "TySON-ID";
67 case TySonType::Objects:
68 return "TySON-Objects";
69 case TySonType::IDs:
70 return "TySON-IDs";
71 case TySonType::Value:
72 return "TySON-Value";
73 case TySonType::ProjectValue:
74 return "TySON-ProjectValue";
75 case TySonType::Keep:
76 return "TySON-Keep";
77 }
78 return "";
79 }
80
86 {
87 std::vector<TySonObject> vector_{};
88 std::map<TySonObject, TySonObject> map_{};
89 std::pair<std::string, std::string> link_{};
90 TySonType type_;
91 std::string value_;
92
101 void parse_vector_elements(std::string_view object) noexcept
102 {
103 const auto to_tyson_object = [](std::string &val) -> TySonObject
104 {
105 return TySonObject{val};
106 };
107
108 auto end_type_sep = object.find_first_of('[') + 1;
109 auto end_value_sep = (object.size() - 1) - end_type_sep;
110
111 auto vector_data = object.substr(end_type_sep, end_value_sep);
112
113 auto vec_data = utils::split(vector_data, ',');
114 std::transform(vec_data.begin(), vec_data.end(), std::back_inserter(vector_), to_tyson_object);
115 }
116
126 [[ nodiscard ]] std::vector<TySonObject> parse_map_element(std::string_view object) noexcept
127 {
128 const auto to_tyson_object = [](std::string &val) -> TySonObject
129 {
130 return TySonObject{val};
131 };
132
133 auto vec_data = utils::split(object, ':');
134
135 std::vector<TySonObject> result;
136 result.reserve(vec_data.size());
137
138 std::transform(vec_data.begin(), vec_data.end(), std::back_inserter(result), to_tyson_object);
139 return result;
140 }
141
150 void parse_map_elements(std::string_view object) noexcept
151 {
152 auto end_type_sep = object.find_first_of('{') + 1;
153 auto end_value_sep = (object.size() - 1) - end_type_sep;
154 auto map_data = object.substr(end_type_sep, end_value_sep);
155
156 auto vec_data = utils::split(map_data, ',');
157
158 auto to_map_element = [this](auto &val) -> std::vector<TySonObject>
159 {
160 return parse_map_element(val);
161 };
162
163 std::vector<std::vector<TySonObject>> result;
164 std::transform(vec_data.begin(), vec_data.end(), std::back_inserter(result), to_map_element);
165 std::for_each(result.begin(), result.end(), [this](auto key_val)
166 {
167 map_.try_emplace(key_val[0], key_val[1]);
168 });
169 }
170
175 friend std::ostream& operator<<(std::ostream &out, TySonObject const &obj) noexcept
176 {
177 switch (obj.type())
178 {
179 case TySonType::Number:
180 return out << "n|" << obj.value_ << "|";
181 case TySonType::String:
182 return out << "s|" << obj.value_ << "|";
183 case TySonType::Bool:
184 return out << "b|" << obj.value_ << "|";
185 case TySonType::Null:
186 return out << "null";
187 case TySonType::Timestamp:
188 return out << "utc|" << obj.value_ << "|";
189 case TySonType::Link:
190 return out << std::get<0>(obj.link_) << "|" << std::get<1>(obj.link_) << "|";
191 case TySonType::Value:
192 return out << "value|" << obj.map_.begin()->first.value_ << "|:" << obj.map_.begin()->second;
193 case TySonType::Vector:
194 {
195 std::stringstream sstream;
196 std::for_each(obj.vector_.begin(),
197 obj.vector_.end(),
198 [&sstream](const auto &val){ sstream << val << ","; });
199
200 return out << "v[" << sstream.str() << "]";
201 }
202 case TySonType::Map:
203 {
204 std::stringstream sstream;
205 std::for_each(obj.map_.begin(),
206 obj.map_.end(),
207 [&sstream](const std::pair<TySonObject, TySonObject> &val)
208 {
209 sstream << val.first << ":" << val.second << ",";
210 });
211
212 return out << "m{" << sstream.str() << "}";
213 }
214 case TySonType::ProjectValue:
215 {
216 return out << "value|" << obj.map_.begin()->first.value_ << "|";
217 }
218 case TySonType::Keep:
219 {
220 return out << "keep";
221 }
222 default:
223 return out << "";
224 }
225 }
226
235 TySonType cast_type_string(char &_type)
236 {
237 switch (_type)
238 {
239 case 'n':
240 return tyson::TySonType::Number;
241 case 's':
242 return tyson::TySonType::String;
243 case 'b':
244 return tyson::TySonType::Bool;
245 case 'u':
246 return tyson::TySonType::Timestamp;
247 case 'l':
248 return tyson::TySonType::Link;
249 case 'v':
250 return tyson::TySonType::Vector;
251 case 'm':
252 return tyson::TySonType::Map;
253 default:
254 return tyson::TySonType::Object;
255 }
256 }
257
258 public:
259
260 TySonObject() noexcept : type_(tyson::TySonType::Null) {};
261 ~TySonObject() = default;
262
269 explicit TySonObject(std::string_view object) noexcept
270 {
271 auto end_type_sep = object.find_first_of('|');
272 auto end_value_sep = (object.size() - 1) - (end_type_sep + 1);
273 auto type = object.substr(0, end_type_sep);
274
275 if (object == "null")
276 {
277 type_ = TySonType::Null;
278 value_ = {};
279 return;
280 }
281
282 if (object.starts_with("uts"))
283 {
284 type_ = TySonType::Timestamp;
285 value_ = object.substr(end_type_sep + 1, end_value_sep);
286 }
287 else if (object.substr(0, 2) == "v[")
288 {
289 type_ = TySonType::Vector;
290
291 parse_vector_elements(object);
292 }
293 else if (object.substr(0, 2) == "m{")
294 {
295 type_ = TySonType::Map;
296 parse_map_elements(object);
297 }
298 else if (end_type_sep > 1)
299 {
300 type_ = TySonType::Link;
301 auto val = object.substr(end_type_sep + 1, end_value_sep);
302 link_ = std::make_pair(type, val);
303 }
304 else
305 {
306 type_ = cast_type_string(const_cast<char &>(type.at(0)));
307 value_ = object.substr(end_type_sep + 1, end_value_sep);
308 }
309 }
310
316 [[ nodiscard ]] bool operator==(const TySonObject &rhs) const noexcept
317 {
318 return std::tie(this->type_, this->value_, this->vector_, this->map_, this->link_) ==
319 std::tie(rhs.type_, rhs.value_, rhs.vector_, rhs.map_, rhs.link_);
320 }
321
327 [[ nodiscard ]] bool operator<(const TySonObject &rhs) const noexcept
328 {
329 return std::tie(this->type_, this->value_, this->vector_) < std::tie(rhs.type_, rhs.value_, rhs.vector_);
330 }
331
338 bool emplace(const std::string &key, tyson::TySonObject &&value)
339 {
340 if (type_ != TySonType::Map)
341 {
342 std::stringstream sstream;
343 sstream << "Can not be used with";
344 sstream << TySonType_repr(type_);
345 throw std::invalid_argument(sstream.str());
346 }
347 const auto [it, success] = map_.try_emplace(TySonObject::String(key), std::move(value));
348 return success;
349 }
350
358 template<typename T>
359 requires std::is_integral_v<T>
360 [[ nodiscard ]] static TySonObject Number(T number) noexcept
361 {
362 TySonObject tySonObject {};
363 tySonObject.value_ = std::to_string(number);
364 tySonObject.type_ = TySonType::Number;
365 return tySonObject;
366 }
367
368
375 [[ nodiscard ]] static TySonObject String(const std::string &str) noexcept
376 {
377 TySonObject tySonObject {};
378 tySonObject.value_ = str;
379 tySonObject.type_ = TySonType::String;
380 return tySonObject;
381 }
382
389 [[ nodiscard ]] static TySonObject Bool(bool bl) noexcept
390 {
391 TySonObject tySonObject {};
392 tySonObject.value_ = bl ? "true" : "false";
393 tySonObject.type_ = TySonType::Bool;
394 return tySonObject;
395 }
396
402 [[ nodiscard ]] static TySonObject Null() noexcept
403 {
404 TySonObject tySonObject {};
405 tySonObject.value_ = "null";
406 tySonObject.type_ = TySonType::Null;
407 return tySonObject;
408 }
409
415 [[ nodiscard ]] static TySonObject Keep() noexcept
416 {
417 TySonObject tySonObject {};
418 tySonObject.value_ = "keep";
419 tySonObject.type_ = TySonType::Keep;
420 return tySonObject;
421 }
422
423
430 [[ nodiscard ]] static TySonObject Timestamp(unsigned long long seconds) noexcept
431 {
432 TySonObject tySonObject {};
433 tySonObject.value_ = std::to_string(seconds);
434 tySonObject.type_ = TySonType::Timestamp;
435 return tySonObject;
436 }
437
445 [[ nodiscard ]] static TySonObject Link(const std::string &collection, const std::string &uuid) noexcept
446 {
447 TySonObject tySonObject {};
448 tySonObject.link_ = {collection, uuid};
449 tySonObject.type_ = TySonType::Link;
450 return tySonObject;
451 }
452
459 template<std::convertible_to<tyson::TySonObject> ...Values>
460 [[ nodiscard ]] static TySonObject Vector(Values &&...objs) noexcept
461 {
462 TySonObject tySonObject {};
463 tySonObject.vector_.reserve(sizeof ...(objs));
464 (tySonObject.vector_.emplace_back(objs), ...);
465 tySonObject.type_ = TySonType::Vector;
466 return tySonObject;
467 }
468
476 [[ nodiscard ]] static TySonObject Value(const std::string &field, TySonObject &&val) noexcept
477 {
478 TySonObject tySonObject {};
479 tySonObject.map_.try_emplace(TySonObject::String(field), val);
480 tySonObject.type_ = TySonType::Value;
481 return tySonObject;
482 }
483
490 [[ nodiscard ]] static TySonObject ProjectValue(const std::string &value) noexcept
491 {
492 TySonObject tySonObject {};
493 tySonObject.map_.try_emplace(TySonObject::String(value), value);
494 tySonObject.type_ = TySonType::ProjectValue;
495 return tySonObject;
496 }
497
504 [[ nodiscard ]] static TySonObject Map(std::map<std::string, TySonObject> &objs) noexcept
505 {
506 TySonObject tySonObject {};
507 std::for_each(objs.begin(), objs.end(),
508 [&tySonObject](std::pair<const std::string, TySonObject> &val)
509 {
510 tySonObject.map_.try_emplace(TySonObject::String(val.first), std::move(val.second));
511 });
512 tySonObject.type_ = TySonType::Map;
513 return tySonObject;
514 }
515
523 [[ nodiscard ]] static TySonObject Map(const std::string &key, TySonObject &&obj) noexcept
524 {
525 TySonObject tySonObject {};
526 tySonObject.map_.try_emplace(TySonObject::String(key), std::move(obj));
527 tySonObject.type_ = TySonType::Map;
528 return tySonObject;
529 }
530
537 [[ nodiscard ]] static TySonObject Map() noexcept
538 {
539 TySonObject tySonObject {};
540 tySonObject.type_ = TySonType::Map;
541 return tySonObject;
542 }
543
550 [[ nodiscard ]] std::optional<TySonObject> operator[](const std::string_view key) const noexcept
551 {
552 if (type_ == TySonType::Map)
553 {
554 TySonObject result;
555 std::for_each(map_.begin(),
556 map_.end(),
557 [&result, &key](const std::pair<TySonObject, TySonObject> &obj)
558 {
559 if (obj.first.value_ == key)
560 {
561 result = obj.second;
562 }
563 });
564 return result;
565 }
566 else
567 {
568 return {};
569 }
570 }
571
576 [[nodiscard]] TySonType type() const noexcept
577 {
578 return type_;
579 }
580
587 template<TySonType T>
588 [[nodiscard]] std::string value() const noexcept
589 {
590 return value_;
591 }
592
599 template<TySonType T>
600 requires (T == TySonType::Bool)
601 [[nodiscard]] bool value() const noexcept
602 {
603 return value_ == "true";
604 }
605
612 template<TySonType T>
613 requires (T == TySonType::Null)
614 [[nodiscard]] std::string value() const noexcept
615 {
616 return "";
617 }
618
625 template<TySonType T>
626 requires (T == TySonType::Link)
627 [[nodiscard]] std::pair<std::string, std::string> value() const noexcept
628 {
629 return link_;
630 }
631
638 template<TySonType T>
639 requires (T == TySonType::Vector)
640 [[nodiscard]] std::vector<TySonObject> value() const noexcept
641 {
642 return vector_;
643 }
644
651 template<TySonType T>
652 requires (T == TySonType::Map)
653 [[nodiscard]] std::map<TySonObject, TySonObject> value() const noexcept
654 {
655 return map_;
656 }
657
665 template<typename T>
666 requires std::is_arithmetic_v<T>
667 [[nodiscard]] T value() const
668 {
669 if (type_ == TySonType::Number || type_ == TySonType::Bool || type_ == TySonType::Timestamp)
670 {
671 std::size_t pos{};
672
673 switch (*typeid(T).name())
674 {
675 case 's':
676 case 'j':
677 case 'i':
678 return std::stoi(value_, &pos);
679 case 'l':
680 return std::stol(value_, &pos);
681 case 'f':
682 return static_cast<T>(std::stof(value_, &pos));
683 case 'd':
684 return static_cast<T>(std::stod(value_, &pos));
685 case 'x':
686 return std::stoll(value_, &pos);
687 case 'e':
688 return static_cast<T>(std::stold(value_, &pos));
689 case 'b':
690 return value_ == "true";
691 case 'c':
692 return value_.c_str()[0];
693 }
694 }
695
696 throw std::invalid_argument("Invalid Type");
697 }
698 };
699
700
702 {
703 std::vector<TySonObject> collection_ids_{};
704 std::vector<std::pair<TySonObject, TySonObject>> collection_objects_{};
705
706 public:
707 TySonCollectionObject() = default;
708 explicit TySonCollectionObject(size_t size, bool objects = false)
709 {
710 if (objects)
711 {
712 collection_objects_.reserve(size);
713 }
714 else
715 {
716 collection_ids_.reserve(size);
717 }
718 }
719 ~TySonCollectionObject() = default;
720
727 void add(const std::string &object)
728 {
729 auto tyson_str_data = utils::split(object, '|');
730 collection_ids_.emplace_back(TySonObject::Link(tyson_str_data[0], tyson_str_data[1]));
731 };
732
739 void add(const std::string &link, const std::string &value)
740 {
741 const auto new_val = std::make_pair(TySonObject(link), TySonObject(value));
742 collection_objects_.emplace_back(new_val);
743 };
744
755 template<TySonType T>
756 requires (T == TySonType::Object)
757 [[ nodiscard ]] std::optional<std::pair<TySonObject, TySonObject>> get(std::string_view obj_id) noexcept
758 {
759 for (const auto &val: collection_objects_)
760 {
761 if (val.first.value<TySonType::Link>().second == obj_id)
762 {
763 return val;
764 }
765 }
766 return {};
767 }
768
776 template<TySonType T>
777 requires (T == TySonType::Objects)
778 [[ nodiscard ]] std::vector<std::pair<TySonObject, TySonObject>> get(std::string_view collection) noexcept
779 {
780 std::vector<std::pair<TySonObject, TySonObject>> result{};
781 std::for_each(collection_objects_.begin(), collection_objects_.end(),
782 [&collection, &result](const std::pair<TySonObject, TySonObject> &val)
783 {
784 if (val.first.value<TySonType::Link>().first == collection)
785 {
786 result.emplace_back(val);
787 }
788 });
789 return result;
790 }
791
800 template<TySonType T>
801 requires (T == TySonType::Object)
802 [[ nodiscard ]] std::optional<std::pair<TySonObject, TySonObject>> get(std::string_view collection, std::string_view obj_id) noexcept
803 {
804 for (const std::pair<TySonObject, TySonObject> &val: collection_objects_)
805 {
806 auto tysonLink = val.first.value<TySonType::Link>();
807 if (std::tie(tysonLink.first, tysonLink.second) == std::tie(collection, obj_id))
808 {
809 return val;
810 }
811 }
812
813 return {};
814 }
815
823 template<TySonType T>
824 requires (T == TySonType::ID)
825 [[ nodiscard ]] std::optional<TySonObject> get(std::string_view obj_id) noexcept
826 {
827 for (const TySonObject &val: collection_ids_)
828 {
829 if (val.value<TySonType::Link>().second == obj_id)
830 {
831 return val;
832 }
833 }
834 return {};
835 }
836
844 template<TySonType T>
845 requires (T == TySonType::IDs)
846 [[ nodiscard ]] std::vector<TySonObject> get(std::string_view collection) noexcept
847 {
848 std::vector<TySonObject> result{};
849 std::for_each(collection_ids_.begin(), collection_ids_.end(),
850 [&result, &collection](const TySonObject &val)
851 {
852 if (val.value<TySonType::Link>().first == collection)
853 {
854 result.emplace_back(val);
855 }
856 });
857 return result;
858 }
859
868 template<TySonType T>
869 requires (T == TySonType::ID)
870 [[ nodiscard ]] std::optional<TySonObject> get(std::string_view collection, std::string_view obj_id) noexcept
871 {
872 for (const TySonObject &val: collection_ids_)
873 {
874 auto tysonLink = val.value<TySonType::Link>();
875 if (std::tie(tysonLink.first, tysonLink.second) == std::tie(collection, obj_id))
876 {
877 return val;
878 }
879 }
880
881 return {};
882 }
883 };
884}
885
886#endif //ANNADB_DRIVER_TYSON_HPP
Definition: TySON.hpp:702
std::optional< std::pair< TySonObject, TySonObject > > get(std::string_view collection, std::string_view obj_id) noexcept
Definition: TySON.hpp:802
std::vector< TySonObject > get(std::string_view collection) noexcept
Definition: TySON.hpp:846
void add(const std::string &link, const std::string &value)
Definition: TySON.hpp:739
std::vector< std::pair< TySonObject, TySonObject > > get(std::string_view collection) noexcept
Definition: TySON.hpp:778
std::optional< TySonObject > get(std::string_view obj_id) noexcept
Definition: TySON.hpp:825
std::optional< TySonObject > get(std::string_view collection, std::string_view obj_id) noexcept
Definition: TySON.hpp:870
void add(const std::string &object)
Definition: TySON.hpp:727
std::optional< std::pair< TySonObject, TySonObject > > get(std::string_view obj_id) noexcept
Definition: TySON.hpp:757
Definition: TySON.hpp:86
T value() const
Definition: TySON.hpp:667
static TySonObject ProjectValue(const std::string &value) noexcept
Definition: TySON.hpp:490
static TySonObject Map(std::map< std::string, TySonObject > &objs) noexcept
Definition: TySON.hpp:504
bool emplace(const std::string &key, tyson::TySonObject &&value)
Definition: TySON.hpp:338
std::pair< std::string, std::string > value() const noexcept
Definition: TySON.hpp:627
TySonObject(std::string_view object) noexcept
Definition: TySON.hpp:269
static TySonObject Null() noexcept
Definition: TySON.hpp:402
bool operator<(const TySonObject &rhs) const noexcept
Definition: TySON.hpp:327
static TySonObject Timestamp(unsigned long long seconds) noexcept
Definition: TySON.hpp:430
std::optional< TySonObject > operator[](const std::string_view key) const noexcept
Definition: TySON.hpp:550
std::map< TySonObject, TySonObject > value() const noexcept
Definition: TySON.hpp:653
std::string value() const noexcept
Definition: TySON.hpp:588
bool operator==(const TySonObject &rhs) const noexcept
Definition: TySON.hpp:316
static TySonObject Map() noexcept
Definition: TySON.hpp:537
static TySonObject Number(T number) noexcept
Definition: TySON.hpp:360
static TySonObject Vector(Values &&...objs) noexcept
Definition: TySON.hpp:460
static TySonObject Link(const std::string &collection, const std::string &uuid) noexcept
Definition: TySON.hpp:445
static TySonObject Keep() noexcept
Definition: TySON.hpp:415
static TySonObject Value(const std::string &field, TySonObject &&val) noexcept
Definition: TySON.hpp:476
TySonType type() const noexcept
Definition: TySON.hpp:576
bool value() const noexcept
Definition: TySON.hpp:601
std::vector< TySonObject > value() const noexcept
Definition: TySON.hpp:640
static TySonObject String(const std::string &str) noexcept
Definition: TySON.hpp:375
std::string value() const noexcept
Definition: TySON.hpp:614
static TySonObject Bool(bool bl) noexcept
Definition: TySON.hpp:389
static TySonObject Map(const std::string &key, TySonObject &&obj) noexcept
Definition: TySON.hpp:523