diff --git a/.gitignore b/.gitignore
index 52a671d..9a8589d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,3 +45,5 @@ build/
 
 **/.DS_Store
 
+# vscode
+.vscode/
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e8ad7d0..ffbbed4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,6 +2,8 @@
 add_library(${OATPP_THIS_MODULE_NAME}
         oatpp-postgresql/mapping/type/Uuid.cpp
         oatpp-postgresql/mapping/type/Uuid.hpp
+        oatpp-postgresql/mapping/type/ByteArray.cpp
+        oatpp-postgresql/mapping/type/ByteArray.hpp
         oatpp-postgresql/mapping/Deserializer.cpp
         oatpp-postgresql/mapping/Deserializer.hpp
         oatpp-postgresql/mapping/Oid.hpp
diff --git a/src/oatpp-postgresql/Executor.cpp b/src/oatpp-postgresql/Executor.cpp
index 5bc94d2..c3fb68b 100644
--- a/src/oatpp-postgresql/Executor.cpp
+++ b/src/oatpp-postgresql/Executor.cpp
@@ -138,14 +138,16 @@ Executor::Executor(const std::shared_ptr<provider::Provider<Connection>>& connec
   , m_resultMapper(std::make_shared<mapping::ResultMapper>())
 {
   m_defaultTypeResolver->addKnownClasses({
-    Uuid::Class::CLASS_ID
+    Uuid::Class::CLASS_ID,
+    ByteArray::Class::CLASS_ID
   });
 }
 
 std::shared_ptr<data::mapping::TypeResolver> Executor::createTypeResolver() {
   auto typeResolver = std::make_shared<data::mapping::TypeResolver>();
   typeResolver->addKnownClasses({
-    Uuid::Class::CLASS_ID
+    Uuid::Class::CLASS_ID,
+    ByteArray::Class::CLASS_ID
   });
   return typeResolver;
 }
diff --git a/src/oatpp-postgresql/Types.hpp b/src/oatpp-postgresql/Types.hpp
index f00c666..9a520b9 100644
--- a/src/oatpp-postgresql/Types.hpp
+++ b/src/oatpp-postgresql/Types.hpp
@@ -26,6 +26,7 @@
 #define oatpp_postgresql_Types_hpp
 
 #include "mapping/type/Uuid.hpp"
+#include "mapping/type/ByteArray.hpp"
 
 namespace oatpp { namespace postgresql {
 
@@ -34,6 +35,11 @@ namespace oatpp { namespace postgresql {
  */
 typedef oatpp::data::mapping::type::Primitive<mapping::type::UuidObject, mapping::type::__class::Uuid> Uuid;
 
+/**
+ * ByteArray as oatpp-postgresql type.
+ */
+typedef oatpp::postgresql::mapping::type::ByteArray ByteArray;
+
 }}
 
 #endif // oatpp_postgresql_Types_hpp
diff --git a/src/oatpp-postgresql/mapping/Deserializer.cpp b/src/oatpp-postgresql/mapping/Deserializer.cpp
index 01bc982..0489456 100644
--- a/src/oatpp-postgresql/mapping/Deserializer.cpp
+++ b/src/oatpp-postgresql/mapping/Deserializer.cpp
@@ -75,7 +75,7 @@ Deserializer::Deserializer() {
   ////
 
   setDeserializerMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Deserializer::deserializeUuid);
-
+  setDeserializerMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Deserializer::deserializeByteArray);
 }
 
 void Deserializer::setDeserializerMethod(const data::mapping::type::ClassId& classId, DeserializerMethod method) {
@@ -268,6 +268,7 @@ const oatpp::Type* Deserializer::guessAnyType(const InData& data) {
     case INT2OID: return oatpp::Int16::Class::getType();
     case INT4OID: return oatpp::Int32::Class::getType();
     case INT8OID: return oatpp::Int64::Class::getType();
+    case BYTEAOID: return oatpp::postgresql::ByteArray::Class::getType();
 
     case FLOAT4OID: return oatpp::Float32::Class::getType();
     case FLOAT8OID: return oatpp::Float64::Class::getType();
@@ -286,6 +287,8 @@ const oatpp::Type* Deserializer::guessAnyType(const InData& data) {
     case INT2ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int16>(data);
     case INT4ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int32>(data);
     case INT8ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int64>(data);
+    case BYTEAARRAYOID:
+      return generateMultidimensionalArrayType<oatpp::postgresql::ByteArray>(data);
 
     case FLOAT4ARRAYOID: return generateMultidimensionalArrayType<oatpp::Float32>(data);
     case FLOAT8ARRAYOID: return generateMultidimensionalArrayType<oatpp::Float64>(data);
@@ -333,6 +336,15 @@ oatpp::Void Deserializer::deserializeUuid(const Deserializer* _this, const InDat
 
 }
 
+oatpp::Void Deserializer::deserializeByteArray(const Deserializer*, const InData &data, const Type*) {
+
+  if (data.isNull || data.size == 0) {
+    return postgresql::ByteArray();
+  }
+
+  return postgresql::ByteArray((p_uint8)data.data, data.size);
+}
+
 oatpp::Void Deserializer::deserializeSubArray(const Type* type,
                                               ArrayDeserializationMeta& meta,
                                               v_int32 dimension)
diff --git a/src/oatpp-postgresql/mapping/Deserializer.hpp b/src/oatpp-postgresql/mapping/Deserializer.hpp
index 2f52c84..a2d54ad 100644
--- a/src/oatpp-postgresql/mapping/Deserializer.hpp
+++ b/src/oatpp-postgresql/mapping/Deserializer.hpp
@@ -108,6 +108,8 @@ class Deserializer {
 
   static oatpp::Void deserializeUuid(const Deserializer* _this, const InData& data, const Type* type);
 
+  static oatpp::Void deserializeByteArray(const Deserializer *_this, const InData &data, const Type *type);
+
   template<typename T>
   static const oatpp::Type* generateMultidimensionalArrayType(const InData& data) {
 
diff --git a/src/oatpp-postgresql/mapping/Serializer.cpp b/src/oatpp-postgresql/mapping/Serializer.cpp
index ab4c623..2f106d9 100644
--- a/src/oatpp-postgresql/mapping/Serializer.cpp
+++ b/src/oatpp-postgresql/mapping/Serializer.cpp
@@ -73,7 +73,7 @@ void Serializer::setSerializerMethods() {
   ////
 
   setSerializerMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::serializeUuid);
-
+  setSerializerMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Serializer::serializeByteArray);
 }
 
 void Serializer::setTypeOidMethods() {
@@ -126,6 +126,8 @@ void Serializer::setTypeOidMethods() {
   setTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid<UUIDOID>);
   setArrayTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid<UUIDARRAYOID>);
 
+  setTypeOidMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Serializer::getTypeOid<BYTEAOID>);
+  setArrayTypeOidMethod(postgresql::mapping::type::__class::ByteArray::CLASS_ID, &Serializer::getTypeOid<BYTEAARRAYOID>);
 }
 
 void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method) {
@@ -462,6 +464,21 @@ void Serializer::serializeUuid(const Serializer* _this, OutputData& outData, con
   }
 }
 
+void Serializer::serializeByteArray(const Serializer *_this, OutputData &outData, const oatpp::Void &polymorph) {
+
+  (void)_this;
+
+  if (polymorph) {
+    auto v = polymorph.cast<oatpp::postgresql::ByteArray>();
+    outData.data = (char*)(v->data());
+    outData.dataSize = static_cast<int>(v->size());
+    outData.dataFormat = 1;
+    outData.oid = BYTEAARRAYOID;
+  } else {
+    serNull(outData);
+  }
+}
+
 const oatpp::Type* Serializer::getArrayItemTypeAndDimensions(const oatpp::Void& polymorph, std::vector<v_int32>& dimensions) {
 
   oatpp::Void curr = polymorph;
diff --git a/src/oatpp-postgresql/mapping/Serializer.hpp b/src/oatpp-postgresql/mapping/Serializer.hpp
index 575e875..479b138 100644
--- a/src/oatpp-postgresql/mapping/Serializer.hpp
+++ b/src/oatpp-postgresql/mapping/Serializer.hpp
@@ -111,6 +111,8 @@ class Serializer {
 
   static void serializeUuid(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph);
 
+  static void serializeByteArray(const Serializer *_this, OutputData &outData, const oatpp::Void &polymorph);
+
   struct ArraySerializationMeta {
 
     const Serializer* _this;
diff --git a/src/oatpp-postgresql/mapping/type/ByteArray.cpp b/src/oatpp-postgresql/mapping/type/ByteArray.cpp
new file mode 100644
index 0000000..c144f88
--- /dev/null
+++ b/src/oatpp-postgresql/mapping/type/ByteArray.cpp
@@ -0,0 +1,87 @@
+/***************************************************************************
+ *
+ * Project         _____    __   ____   _      _
+ *                (  _  )  /__\ (_  _)_| |_  _| |_
+ *                 )(_)(  /(__)\  )( (_   _)(_   _)
+ *                (_____)(__)(__)(__)  |_|    |_|
+ *
+ *
+ * Copyright 2018-present
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ***************************************************************************/
+
+#include "ByteArray.hpp"
+
+#include "oatpp/core/data/stream/BufferStream.hpp"
+#include "oatpp/encoding/Base64.hpp"
+#include "oatpp/encoding/Hex.hpp"
+
+namespace oatpp {
+namespace postgresql {
+namespace mapping {
+namespace type {
+
+namespace __class {
+const ClassId ByteArray::CLASS_ID("oatpp::postgresql::ByteArray");
+}
+
+ByteArray::ByteArray(const std::shared_ptr<std::vector<v_uint8>> &ptr, const _oatpp_Type *const valueType)
+    : oatpp::data::mapping::type::ObjectWrapper<std::vector<v_uint8>, __class::ByteArray>(ptr) {
+    if (type::__class::ByteArray::getType() != valueType) {
+        throw std::runtime_error("Value type does not match");
+    }
+}
+
+ByteArray ByteArray::fromHexEncodedString(const String &hexEncodedString) {
+    const v_buff_usize expected_bytes_number = hexEncodedString->size() / 2;
+
+    data::stream::BufferOutputStream stream(default_buffer_size);
+    encoding::Hex::decode(&stream, hexEncodedString->data(), hexEncodedString->size(), true);
+    if (stream.getCurrentPosition() != expected_bytes_number) {
+        throw std::invalid_argument("[oatpp::postgresql::mapping::type::ByteArray::fromHexEncodedString(String)]:"
+                                    "Error. Invalid string.");
+    }
+
+    return ByteArray((const v_uint8 *)stream.getData(), expected_bytes_number);
+}
+
+ByteArray ByteArray::fromBase64EncodedString(const String &base64EncodedString) {
+    const auto tb = encoding::Base64::decode(base64EncodedString);
+    return ByteArray(reinterpret_cast<const v_uint8 *>(tb->data()), tb->size());
+}
+
+String toBase64EncodedString(const ByteArray &arr) {
+
+    if (arr->empty()) {
+        return String();
+    }
+    return encoding::Base64::encode(arr->data(), arr->size());
+}
+
+String toHexEncodedString(const ByteArray &arr) {
+
+    if (arr->empty()) {
+        return String();
+    }
+
+    oatpp::data::stream::BufferOutputStream stream(ByteArray::default_buffer_size);
+    encoding::Hex::encode(&stream, arr->data(), arr->size());
+
+    return stream.toString();
+}
+} // namespace type
+} // namespace mapping
+} // namespace postgresql
+} // namespace oatpp
diff --git a/src/oatpp-postgresql/mapping/type/ByteArray.hpp b/src/oatpp-postgresql/mapping/type/ByteArray.hpp
new file mode 100644
index 0000000..6d9c3ec
--- /dev/null
+++ b/src/oatpp-postgresql/mapping/type/ByteArray.hpp
@@ -0,0 +1,191 @@
+/***************************************************************************
+ *
+ * Project         _____    __   ____   _      _
+ *                (  _  )  /__\ (_  _)_| |_  _| |_
+ *                 )(_)(  /(__)\  )( (_   _)(_   _)
+ *                (_____)(__)(__)(__)  |_|    |_|
+ *
+ *
+ * Copyright 2018-present
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ***************************************************************************/
+
+#ifndef oatpp_data_mapping_type_ByteArray_hpp
+#define oatpp_data_mapping_type_ByteArray_hpp
+
+#include "oatpp/core/Types.hpp"
+#include "oatpp/core/data/mapping/type/Primitive.hpp"
+#include "oatpp/core/data/mapping/type/Type.hpp"
+
+#include <cassert>
+#include <cstdint>
+#include <initializer_list>
+#include <memory>
+#include <vector>
+
+namespace oatpp {
+namespace postgresql {
+namespace mapping {
+namespace type {
+
+namespace __class {
+
+/**
+ * ByteArray Class.
+ */
+class ByteArray {
+  public:
+    /**
+     * Class Id
+     */
+    static const ClassId CLASS_ID;
+
+    static Type *getType() {
+        static Type type(CLASS_ID);
+        return &type;
+    }
+};
+} // namespace __class
+
+/**
+ * Mapping - enables ByteArray is &id:type::ObjectWrapper; over `std::vector<v_uint8>`;
+ */
+class ByteArray : public oatpp::data::mapping::type::ObjectWrapper<std::vector<v_uint8>, __class::ByteArray> {
+    using ObjectWrapper::ObjectWrapper;
+    using _oatpp_Type = oatpp::data::mapping::type::Type;
+
+  public:
+    static constexpr v_buff_usize default_buffer_size = 1024U;
+
+    ByteArray() = default;
+    ~ByteArray() = default;
+
+    ByteArray(const std::shared_ptr<std::vector<v_uint8>> &ptr, const _oatpp_Type *const valueType);
+
+    explicit ByteArray(v_buff_usize size)
+        : oatpp::data::mapping::type::ObjectWrapper<std::vector<v_uint8>, __class::ByteArray>(
+              std::make_shared<std::vector<v_uint8>>(size, 0)) {}
+
+    ByteArray(const v_uint8 *data, v_buff_usize size)
+        : oatpp::data::mapping::type::ObjectWrapper<std::vector<v_uint8>, __class::ByteArray>(
+              std::make_shared<std::vector<v_uint8>>(data, data + size * sizeof(v_uint8))) {}
+
+    ByteArray(std::initializer_list<v_uint8> ilist)
+        : oatpp::data::mapping::type::ObjectWrapper<std::vector<v_uint8>, __class::ByteArray>(
+              std::make_shared<std::vector<v_uint8>>(ilist)) {}
+
+    ByteArray &operator=(std::initializer_list<v_uint8> ilist) {
+        this->m_ptr = std::make_shared<std::vector<v_uint8>>(ilist);
+        return *this;
+    }
+
+    ByteArray(const ByteArray &other) = default;
+    inline ByteArray &operator=(const ByteArray &other) {
+        m_ptr = other.m_ptr;
+        return *this;
+    }
+
+    ByteArray(ByteArray &&other) = default;
+    inline ByteArray &operator=(ByteArray &&other) noexcept {
+        m_ptr = std::move(other.m_ptr);
+        return *this;
+    }
+
+    /**
+     * @brief Creates ByteArray from the HEX encoded string
+     *
+     * @return ByteArray
+     */
+    static ByteArray fromHexEncodedString(const String &hexEncodedString);
+
+    /**
+     * @brief Creates ByteArray from the Base64 encoded string
+     *
+     * @return ByteArray
+     */
+    static ByteArray fromBase64EncodedString(const String &base64EncodedString);
+
+    /**
+     * @brief Create a shared object of empty ByteArray
+     *
+     * @return ByteArray
+     */
+    static ByteArray createShared() { return std::make_shared<std::vector<v_uint8>>(); }
+
+    /**
+     * @brief Get constant reference to underlying container
+     *
+     * @return const std::vector<v_uint8>&
+     */
+    const std::vector<v_uint8> &operator*() const {
+        assert(this->m_ptr);
+        return this->m_ptr.operator*();
+    }
+
+    inline ByteArray &operator=(const std::vector<v_uint8> &str) {
+        m_ptr = std::make_shared<std::vector<v_uint8>>(str);
+        return *this;
+    }
+
+    inline ByteArray &operator=(std::vector<v_uint8> &&str) {
+        m_ptr = std::make_shared<std::vector<v_uint8>>(std::move(str));
+        return *this;
+    }
+
+    inline bool operator==(const std::vector<v_uint8> &str) const {
+        if (!m_ptr) {
+            return false;
+        }
+        return *m_ptr == str;
+    }
+
+    inline bool operator!=(const std::vector<v_uint8> &str) const { return !operator==(str); }
+
+    inline bool operator==(const ByteArray &other) const {
+        if (!m_ptr) {
+            return !other.m_ptr;
+        }
+
+        if (!other.m_ptr) {
+            return false;
+        }
+        return *m_ptr == *other.m_ptr;
+    }
+
+    inline bool operator!=(const ByteArray &other) const { return !operator==(other); }
+};
+
+/**
+ * @brief Converts ByteArray to the base64 encoded string
+ *
+ * @param b input ByteArray to convert to Base64 encoded string
+ * @return String
+ */
+String toBase64EncodedString(const ByteArray &b);
+
+/**
+ * @brief Converts ByteArray to the string of symbols representing hex-encoded bytes
+ *
+ * @param b input ByteArray to convert to HEX encoded string
+ * @return String
+ */
+String toHexEncodedString(const ByteArray &b);
+
+} // namespace type
+} // namespace mapping
+} // namespace postgresql
+} // namespace oatpp
+
+#endif // oatpp_data_mapping_type_ByteArray_hpp
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ba2892a..1928e52 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -24,6 +24,10 @@ add_executable(module-tests
         oatpp-postgresql/types/IntTest.hpp
         oatpp-postgresql/types/CharacterTest.cpp
         oatpp-postgresql/types/CharacterTest.hpp
+        oatpp-postgresql/types/ByteArrayTest.cpp
+        oatpp-postgresql/types/ByteArrayTest.hpp
+        oatpp-postgresql/types/ByteArrayTypeTest.cpp
+        oatpp-postgresql/types/ByteArrayTypeTest.hpp
         oatpp-postgresql/tests.cpp
         )
 
diff --git a/test/oatpp-postgresql/migration/ByteArrayTest.sql b/test/oatpp-postgresql/migration/ByteArrayTest.sql
new file mode 100644
index 0000000..ca88b4f
--- /dev/null
+++ b/test/oatpp-postgresql/migration/ByteArrayTest.sql
@@ -0,0 +1,5 @@
+DROP TABLE IF EXISTS test_bytearray;
+
+CREATE TABLE test_bytearray (
+    f_bytea  bytea
+);
diff --git a/test/oatpp-postgresql/tests.cpp b/test/oatpp-postgresql/tests.cpp
index 504ce2b..1d3e4a9 100644
--- a/test/oatpp-postgresql/tests.cpp
+++ b/test/oatpp-postgresql/tests.cpp
@@ -2,8 +2,10 @@
 #include "ql_template/ParserTest.hpp"
 
 #include "types/ArrayTest.hpp"
-#include "types/IntTest.hpp"
+#include "types/ByteArrayTest.hpp"
+#include "types/ByteArrayTypeTest.hpp"
 #include "types/FloatTest.hpp"
+#include "types/IntTest.hpp"
 #include "types/InterpretationTest.hpp"
 #include "types/CharacterTest.hpp"
 
@@ -42,7 +44,8 @@ void runTests() {
   OATPP_RUN_TEST(oatpp::test::postgresql::types::ArrayTest);
   OATPP_RUN_TEST(oatpp::test::postgresql::types::InterpretationTest);
   OATPP_RUN_TEST(oatpp::test::postgresql::types::CharacterTest);
-
+  OATPP_RUN_TEST(oatpp::test::postgresql::types::ByteArrayTypeTest);
+  OATPP_RUN_TEST(oatpp::test::postgresql::types::ByteArrayTest);
 }
 
 }
diff --git a/test/oatpp-postgresql/types/ByteArrayTest.cpp b/test/oatpp-postgresql/types/ByteArrayTest.cpp
new file mode 100644
index 0000000..a108c08
--- /dev/null
+++ b/test/oatpp-postgresql/types/ByteArrayTest.cpp
@@ -0,0 +1,154 @@
+/***************************************************************************
+ *
+ * Project         _____    __   ____   _      _
+ *                (  _  )  /__\ (_  _)_| |_  _| |_
+ *                 )(_)(  /(__)\  )( (_   _)(_   _)
+ *                (_____)(__)(__)(__)  |_|    |_|
+ *
+ *
+ * Copyright 2018-present
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ***************************************************************************/
+
+#include "ByteArrayTest.hpp"
+
+#include "oatpp-postgresql/Types.hpp"
+#include "oatpp-postgresql/orm.hpp"
+#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
+
+#include <cstdio>
+#include <limits>
+#include <vector>
+
+namespace oatpp {
+namespace test {
+namespace postgresql {
+namespace types {
+
+namespace {
+
+#include OATPP_CODEGEN_BEGIN(DTO)
+
+class MyByteArrayRow : public oatpp::DTO {
+
+    DTO_INIT(MyByteArrayRow, DTO);
+
+    DTO_FIELD(oatpp::postgresql::ByteArray, f_bytea);
+};
+
+#include OATPP_CODEGEN_END(DTO)
+
+#include OATPP_CODEGEN_BEGIN(DbClient)
+
+class MyClient : public oatpp::orm::DbClient {
+  public:
+    MyClient(const std::shared_ptr<oatpp::orm::Executor> &executor) : oatpp::orm::DbClient(executor) {
+
+        executeQuery("DROP TABLE IF EXISTS oatpp_schema_version_ByteArrayTest;", {});
+
+        oatpp::orm::SchemaMigration migration(executor, "ByteArrayTest");
+        migration.addFile(1, TEST_DB_MIGRATION "ByteArrayTest.sql");
+        migration.migrate();
+
+        auto version = executor->getSchemaVersion("ByteArrayTest");
+        OATPP_LOGD("DbClient", "Migration - OK. Version=%d.", version);
+    }
+
+    QUERY(insertBytearrayValues,
+          "INSERT INTO test_bytearray "
+          "(f_bytea) "
+          "VALUES "
+          "(:f_bytea);",
+          PREPARE(true), PARAM(oatpp::postgresql::ByteArray, f_bytea))
+
+    QUERY(selectAllBytearray, "SELECT f_bytea FROM test_bytearray")
+};
+
+#include OATPP_CODEGEN_END(DbClient)
+
+} // namespace
+
+void ByteArrayTest::onRun() {
+
+    OATPP_LOGI(TAG, "DB-URL='%s'", TEST_DB_URL);
+
+    auto connectionProvider = std::make_shared<oatpp::postgresql::ConnectionProvider>(TEST_DB_URL);
+    auto executor = std::make_shared<oatpp::postgresql::Executor>(connectionProvider);
+    auto client = MyClient(executor);
+
+    const auto one_element_byte_array = oatpp::postgresql::ByteArray({0xAA});
+    const auto two_elements_byte_array = oatpp::postgresql::ByteArray({0xAA, 0xBB});
+    const auto three_elements_byte_array = oatpp::postgresql::ByteArray({0xDE, 0xAD, 0xBE});
+    const auto four_elements_byte_array = oatpp::postgresql::ByteArray({0xDE, 0xAD, 0xBE, 0xEF});
+
+    {
+        auto connection = client.getConnection();
+
+        client.insertBytearrayValues(oatpp::postgresql::ByteArray(), connection);
+        client.insertBytearrayValues(one_element_byte_array, connection);
+        client.insertBytearrayValues(two_elements_byte_array, connection);
+        client.insertBytearrayValues(three_elements_byte_array, connection);
+        client.insertBytearrayValues(four_elements_byte_array, connection);
+    }
+
+    {
+        auto res = client.selectAllBytearray();
+        if (res->isSuccess()) {
+            OATPP_LOGD(TAG, "OK, knownCount=%d, hasMore=%d", res->getKnownCount(), res->hasMoreToFetch());
+        } else {
+            auto message = res->getErrorMessage();
+            OATPP_LOGD(TAG, "Error, message=%s", message->c_str());
+        }
+
+        auto dataset = res->fetch<oatpp::Vector<oatpp::Object<MyByteArrayRow>>>();
+
+        OATPP_ASSERT(dataset->size() == 5);
+
+        {
+            const auto &row = dataset[0];
+            OATPP_ASSERT(row->f_bytea == oatpp::postgresql::ByteArray());
+        }
+
+        {
+            const auto &row = dataset[1];
+
+            OATPP_ASSERT(row->f_bytea->size() == one_element_byte_array->size());
+            OATPP_ASSERT(*(row->f_bytea) == *(one_element_byte_array));
+        }
+        {
+            const auto &row = dataset[2];
+
+            OATPP_ASSERT(row->f_bytea->size() == two_elements_byte_array->size());
+            OATPP_ASSERT(*(row->f_bytea) == *(two_elements_byte_array));
+        }
+        {
+            const auto &row = dataset[3];
+
+            OATPP_ASSERT(row->f_bytea->size() == three_elements_byte_array->size());
+            OATPP_ASSERT(*(row->f_bytea) == *(three_elements_byte_array));
+        }
+        {
+            const auto &row = dataset[4];
+
+            OATPP_ASSERT(row->f_bytea->size() == four_elements_byte_array->size());
+            OATPP_ASSERT(*(row->f_bytea) == *(four_elements_byte_array));
+        }
+    }
+}
+
+} // namespace types
+} // namespace postgresql
+} // namespace test
+} // namespace oatpp
diff --git a/test/oatpp-postgresql/types/ByteArrayTest.hpp b/test/oatpp-postgresql/types/ByteArrayTest.hpp
new file mode 100644
index 0000000..3c6cca5
--- /dev/null
+++ b/test/oatpp-postgresql/types/ByteArrayTest.hpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Project         _____    __   ____   _      _
+ *                (  _  )  /__\ (_  _)_| |_  _| |_
+ *                 )(_)(  /(__)\  )( (_   _)(_   _)
+ *                (_____)(__)(__)(__)  |_|    |_|
+ *
+ *
+ * Copyright 2018-present
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ***************************************************************************/
+
+#ifndef oatpp_test_postgresql_types_ByteArrayTest_hpp
+#define oatpp_test_postgresql_types_ByteArrayTest_hpp
+
+#include "oatpp-test/UnitTest.hpp"
+
+namespace oatpp {
+namespace test {
+namespace postgresql {
+namespace types {
+
+class ByteArrayTest : public UnitTest {
+  public:
+    ByteArrayTest() : UnitTest("TEST[postgresql::types::ByteArrayTest]") {}
+    void onRun() override;
+};
+
+} // namespace types
+} // namespace postgresql
+} // namespace test
+} // namespace oatpp
+
+#endif // oatpp_test_postgresql_types_ByteArrayTest_hpp
diff --git a/test/oatpp-postgresql/types/ByteArrayTypeTest.cpp b/test/oatpp-postgresql/types/ByteArrayTypeTest.cpp
new file mode 100644
index 0000000..afd4c02
--- /dev/null
+++ b/test/oatpp-postgresql/types/ByteArrayTypeTest.cpp
@@ -0,0 +1,286 @@
+/***************************************************************************
+ *
+ * Project         _____    __   ____   _      _
+ *                (  _  )  /__\ (_  _)_| |_  _| |_
+ *                 )(_)(  /(__)\  )( (_   _)(_   _)
+ *                (_____)(__)(__)(__)  |_|    |_|
+ *
+ *
+ * Copyright 2018-present
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ***************************************************************************/
+
+#include "ByteArrayTypeTest.hpp"
+
+#include "oatpp-postgresql/Types.hpp"
+
+#include <array>
+
+namespace oatpp {
+namespace test {
+namespace postgresql {
+namespace types {
+
+void ByteArrayTypeTest::onRun() {
+
+    {
+        OATPP_LOGI(TAG, "test default constructor...");
+        oatpp::postgresql::ByteArray array;
+
+        OATPP_ASSERT(!array);
+        OATPP_ASSERT(array == nullptr);
+
+        OATPP_ASSERT(array.get() == nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test empty ilist constructor...");
+        oatpp::postgresql::ByteArray array({});
+
+        OATPP_ASSERT(array);
+        OATPP_ASSERT(array != nullptr);
+        OATPP_ASSERT(array->size() == 0);
+
+        OATPP_ASSERT(array.get() != nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test constructor from shared_ptr to empty vector...");
+        oatpp::postgresql::ByteArray array(std::make_shared<std::vector<v_uint8>>());
+
+        OATPP_ASSERT(array);
+        OATPP_ASSERT(array != nullptr);
+        OATPP_ASSERT(array->size() == 0);
+
+        OATPP_ASSERT(array.get() != nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test constructor from shared_ptr to non-empty vector...");
+        std::vector<v_uint8> v = {0xA, 0xB, 0xC, 0xD};
+        oatpp::postgresql::ByteArray array(std::make_shared<std::vector<v_uint8>>(v));
+
+        OATPP_ASSERT(array);
+        OATPP_ASSERT(array != nullptr);
+        OATPP_ASSERT(array->size() == v.size());
+
+        OATPP_ASSERT(array.get() != nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+
+        OATPP_ASSERT(array->at(0) == v.at(0));
+        OATPP_ASSERT(array->at(v.size() - 1) == v.at(v.size() - 1));
+
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test assign operator with non-empty vector...");
+        oatpp::postgresql::ByteArray array = {0xA, 0xB, 0xC, 0xD};
+        const auto arr_size = 4U;
+
+        OATPP_ASSERT(array);
+        OATPP_ASSERT(array != nullptr);
+        OATPP_ASSERT(array->size() == arr_size);
+
+        OATPP_ASSERT(array.get() != nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+
+        OATPP_ASSERT(array->at(0) == 0xA);
+        OATPP_ASSERT(array->at(arr_size - 1) == 0xD);
+
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test constructor creating some buffer initialized with zeroes...");
+        const auto buf_size = 11U;
+        oatpp::postgresql::ByteArray array(buf_size);
+
+        OATPP_ASSERT(array);
+        OATPP_ASSERT(array != nullptr);
+        OATPP_ASSERT(array->size() == buf_size);
+
+        OATPP_ASSERT(array.get() != nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+
+        for (auto i = 0; i < buf_size; i++) {
+            OATPP_ASSERT(array->at(i) == 0);
+        }
+
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test constructor creating converting data from some array...");
+        const auto buf_size = 5U;
+        constexpr std::array<v_uint8, buf_size> buffer = {0x1, 0x2, 0x3, 0x4, 0x5};
+        oatpp::postgresql::ByteArray array(buffer.data(), buf_size);
+
+        OATPP_ASSERT(array);
+        OATPP_ASSERT(array != nullptr);
+        OATPP_ASSERT(array->size() == buf_size);
+
+        OATPP_ASSERT(array.get() != nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+
+        for (auto i = 0; i < buf_size; i++) {
+            OATPP_ASSERT(array->at(i) == i + 1);
+        }
+
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test createShared()...");
+        auto array = oatpp::postgresql::ByteArray::createShared();
+
+        OATPP_ASSERT(array);
+        OATPP_ASSERT(array != nullptr);
+        OATPP_ASSERT(array->size() == 0);
+
+        OATPP_ASSERT(array.get() != nullptr);
+        OATPP_ASSERT(array.getValueType() == oatpp::postgresql::ByteArray::Class::getType());
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test copy-assignment operator...");
+        oatpp::postgresql::ByteArray array1({});
+        oatpp::postgresql::ByteArray array2;
+
+        array2 = array1;
+
+        OATPP_ASSERT(array1);
+        OATPP_ASSERT(array2);
+
+        OATPP_ASSERT(array1->size() == 0);
+        OATPP_ASSERT(array2->size() == 0);
+
+        OATPP_ASSERT(array1.get() == array2.get());
+
+        array2->push_back(0xA);
+
+        OATPP_ASSERT(array1->size() == 1);
+        OATPP_ASSERT(array2->size() == 1);
+        OATPP_ASSERT(array2->at(0) == 0xA);
+        OATPP_ASSERT(array1->at(0) == 0xA);
+
+        std::vector<v_uint8> v2{0xB, 0xC};
+        array2 = v2;
+
+        OATPP_ASSERT(array1->size() == 1);
+        OATPP_ASSERT(array2->size() == 2);
+
+        OATPP_ASSERT(array2->at(0) == 0xB);
+        OATPP_ASSERT(array2->at(1) == 0xC);
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test move-assignment operator...");
+        oatpp::postgresql::ByteArray array1({});
+        oatpp::postgresql::ByteArray array2;
+        OATPP_ASSERT(!array2);
+
+        array2 = std::move(array1);
+
+        OATPP_ASSERT(!array1);
+        OATPP_ASSERT(array2);
+        OATPP_LOGI(TAG, "OK");
+    }
+
+    {
+        OATPP_LOGI(TAG, "test toHexEncodedString method...");
+        oatpp::postgresql::ByteArray array1(
+            {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF});
+
+        OATPP_ASSERT(array1);
+        OATPP_ASSERT(array1->size() == 16);
+
+        const auto s1 = toHexEncodedString(array1);
+        OATPP_LOGI(TAG, "arr.toHexEncodedString returned %s", s1->c_str());
+        OATPP_ASSERT(oatpp::String("000102030405060708090A0B0C0D0E0F") == s1);
+
+        oatpp::postgresql::ByteArray array2(
+            {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF});
+
+        OATPP_ASSERT(array2);
+        OATPP_ASSERT(array2->size() == 16);
+
+        const auto s2 = toHexEncodedString(array2);
+        OATPP_LOGI(TAG, "arr.toHexEncodedString returned %s", s2->c_str());
+        OATPP_ASSERT(oatpp::String("AABBCCDDEEFF060708090A0B0C0D0E0F") == s2);
+    }
+
+    {
+        OATPP_LOGI(TAG, "test fromHexEncodedString method...");
+        const std::vector<uint8_t> ba_result = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+                                                0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};
+        const auto in_string = oatpp::String("000102030405060708090A0B0C0D0E0F");
+
+        const auto a = oatpp::postgresql::ByteArray::fromHexEncodedString(in_string);
+
+        OATPP_ASSERT(a);
+        OATPP_ASSERT(a->size() == 16);
+        OATPP_ASSERT(a == ba_result);
+    }
+
+    {
+        OATPP_LOGI(TAG, "test toBase64EncodedString method...");
+        oatpp::postgresql::ByteArray array1(
+            {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF});
+
+        OATPP_ASSERT(array1);
+        OATPP_ASSERT(array1->size() == 16);
+
+        const auto s1 = toBase64EncodedString(array1);
+        OATPP_LOGI(TAG, "arr.toBase64EncodedString returned %s", s1->c_str());
+        OATPP_ASSERT(oatpp::String("AAECAwQFBgcICQoLDA0ODw==") == s1);
+
+        oatpp::postgresql::ByteArray array2({0xAA, 0xBB, 0xCC, 0xDD, 0xEE});
+
+        OATPP_ASSERT(array2);
+        OATPP_ASSERT(array2->size() == 5);
+
+        const auto s2 = toBase64EncodedString(array2);
+        OATPP_LOGI(TAG, "arr.toBase64EncodedString returned %s", s2->c_str());
+        OATPP_ASSERT(oatpp::String("qrvM3e4=") == s2);
+    }
+
+    {
+        OATPP_LOGI(TAG, "test fromBase64EncodedString method...");
+        const std::vector<uint8_t> ba_result = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+                                                0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};
+        const auto in_string = oatpp::String("AAECAwQFBgcICQoLDA0ODw==");
+
+        const auto a = oatpp::postgresql::ByteArray::fromBase64EncodedString(in_string);
+
+        OATPP_ASSERT(a);
+        OATPP_ASSERT(a->size() == ba_result.size());
+        OATPP_ASSERT(a == ba_result);
+    }
+}
+
+} // namespace types
+} // namespace postgresql
+} // namespace test
+} // namespace oatpp
diff --git a/test/oatpp-postgresql/types/ByteArrayTypeTest.hpp b/test/oatpp-postgresql/types/ByteArrayTypeTest.hpp
new file mode 100644
index 0000000..93a684d
--- /dev/null
+++ b/test/oatpp-postgresql/types/ByteArrayTypeTest.hpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Project         _____    __   ____   _      _
+ *                (  _  )  /__\ (_  _)_| |_  _| |_
+ *                 )(_)(  /(__)\  )( (_   _)(_   _)
+ *                (_____)(__)(__)(__)  |_|    |_|
+ *
+ *
+ * Copyright 2018-present
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ***************************************************************************/
+
+#ifndef oatpp_test_core_data_mapping_type_ByteArrayTypeTest_hpp
+#define oatpp_test_core_data_mapping_type_ByteArrayTypeTest_hpp
+
+#include "oatpp-test/UnitTest.hpp"
+
+namespace oatpp {
+namespace test {
+namespace postgresql {
+namespace types {
+
+class ByteArrayTypeTest : public UnitTest {
+  public:
+    ByteArrayTypeTest() : UnitTest("TEST[oatpp::test::postgresql::types::ByteArrayTypeTest]") {}
+    void onRun() override;
+};
+
+} // namespace types
+} // namespace postgresql
+} // namespace test
+} // namespace oatpp
+
+#endif /* oatpp_test_core_data_mapping_type_ByteArrayTypeTest_hpp */