#ifndef PGSQL_VALUE_H #define PGSQL_VALUE_H #include "Pgsql_declare.h" #include "Pgsql_oids.h" #include "ArrayParser.h" #include #include #include #include #include namespace Pgsql { template E StringToArrayElem(std::string_view sv); /** \brief Class that is returned as value of a cell to facilitate auto conversion. */ class Value { public: const char *empty_str = ""; Value(const char *val, Oid typ); QString asQString() const; bool null() const { return m_val == nullptr; } const char* c_str() const { return m_val == nullptr ? empty_str : m_val; } operator QString() const; operator QDateTime() const; operator QDate() const; operator QTime() const; operator std::string() const; operator int16_t() const; operator int32_t() const; operator Oid() const; operator int64_t() const; operator bool() const; operator float() const; operator double() const; operator char() const; bool isString() const; /// Retrieves an array type value and passes them to an insert iterator. /// /// When the array it self is NULL this function behaves the same as for an empty array. No /// elements are given to the insert iterator and the function returns. Use the null() function /// to check for NULL values. /// /// \param insert_iter An insert_iterator which is used to add the elements of the array to a container. /// \param nullhandling This only affects how NULL elements within the array are handled. template void getAsArray(I insert_iter, NullHandling nullhandling = NullHandling::Throw) const { if (m_val == nullptr) { return; } else { using value_type = E; ArrayParser parser(m_val, -1); for (;;) { auto res = parser.GetNextElem(); if (res.ok) { if (res.value) { insert_iter = StringToArrayElem(*res.value); } else { if (nullhandling == NullHandling::Throw) throw std::runtime_error("Unexpected NULL value in array"); } } else break; } } } /// Retrieves an array typed value, and passes the element to the insert iterator /// /// \param value_for_nulls Each time it encounters a NULL element in the array it /// will instead pass this value to the insert iterator. template void getAsArray(I insert_iter, const E &value_for_nulls) const { if (m_val == nullptr) return; using value_type = E; ArrayParser parser(m_val, -1); for (;;) { auto res = parser.GetNextElem(); if (res.ok) { if (res.value) { insert_iter = StringToArrayElem(*res.value); } else { insert_iter = value_for_nulls; } } else break; } } /// Retrieves an array typed value, and passes the elements to the insert iterator template void getAsArrayOfOptional(I insert_iter) const { if (m_val == nullptr) return; using value_type = E; ArrayParser parser(m_val, -1); for (;;) { auto res = parser.GetNextElem(); if (res.ok) { if (res.value) { insert_iter = StringToArrayElem(*res.value); } else { insert_iter = std::nullopt; } } else break; } } /// De catalog uses vector types which are similar to array /// but uses spaces as seperators. AFAIK there are only integral /// vector types so this implementation is only tested for those template void getAsVector(I insert_iter) const { if (m_val == nullptr || *m_val == '\0') return; const char * pos = m_val; const char * start = pos; for (;;) { while (*pos != 0 && *pos != ' ') ++pos; // The cast (to prevent warning) should be save as start should always be <= pos insert_iter = StringToArrayElem(std::string_view(start, static_cast(pos-start))); if (*pos == 0) break; start = ++pos; // skip space and set new start to match } } inline Oid getOid() const { return m_typ; } private: const char *m_val; Oid m_typ; }; template void operator<<(std::optional &s, const Value &v) { if (v.null()) s = std::optional(); else s = v.operator T(); } template void operator<<(std::vector &s, const Value &v) { v.getAsArray(std::back_inserter(s)); } template void operator<<(T &s, const Value &v) { s = v.operator T(); } template E StringToArrayElem(std::string_view sv) { std::string str(sv.data(), sv.length()); Value val(str.c_str(), OidFor::elem()); E v; v << val; return v; } } // end namespace Pgsql #endif // PGSQL_VALUE_H