Browse Source

Update drogon (#5134)

An Tao 5 years ago
parent
commit
4dc39c299f

+ 1 - 1
frameworks/C++/drogon/drogon-core.dockerfile

@@ -44,7 +44,7 @@ RUN git clone https://github.com/an-tao/drogon
 
 WORKDIR $DROGON_ROOT
 
-RUN git checkout aa26e9a90388b6a6fe5356e2d12b6f6091c82818
+RUN git checkout df82728a452ce9dab568d975991e9a0afb41a98f
 RUN git submodule update --init
 RUN mkdir build
 

+ 1 - 1
frameworks/C++/drogon/drogon.dockerfile

@@ -44,7 +44,7 @@ RUN git clone https://github.com/an-tao/drogon
 
 WORKDIR $DROGON_ROOT
 
-RUN git checkout aa26e9a90388b6a6fe5356e2d12b6f6091c82818
+RUN git checkout df82728a452ce9dab568d975991e9a0afb41a98f
 RUN git submodule update --init
 RUN mkdir build
 

+ 390 - 26
frameworks/C++/drogon/drogon_benchmark/models/Fortune.cc

@@ -12,8 +12,8 @@
 using namespace drogon;
 using namespace drogon_model::hello_world;
 
-const std::string Fortune::Cols::id = "id";
-const std::string Fortune::Cols::message = "message";
+const std::string Fortune::Cols::_id = "id";
+const std::string Fortune::Cols::_message = "message";
 const std::string Fortune::primaryKeyName = "id";
 const bool Fortune::hasPrimaryKey = true;
 const std::string Fortune::tableName = "fortune";
@@ -26,18 +26,145 @@ const std::string &Fortune::getColumnName(size_t index) noexcept(false)
     assert(index < _metaData.size());
     return _metaData[index]._colName;
 }
-Fortune::Fortune(const Row &r) noexcept
+Fortune::Fortune(const Row &r, const ssize_t indexOffset) noexcept
 {
-    if (!r["id"].isNull())
+    if (indexOffset < 0)
     {
-        _id = std::make_shared<int32_t>(r["id"].as<int32_t>());
+        if (!r["id"].isNull())
+        {
+            _id = std::make_shared<int32_t>(r["id"].as<int32_t>());
+        }
+        if (!r["message"].isNull())
+        {
+            _message =
+                std::make_shared<std::string>(r["message"].as<std::string>());
+        }
     }
-    if (!r["message"].isNull())
+    else
     {
-        _message =
-            std::make_shared<std::string>(r["message"].as<std::string>());
+        size_t offset = (size_t)indexOffset;
+        if (offset + 2 > r.size())
+        {
+            LOG_FATAL << "Invalid SQL result for this model";
+            return;
+        }
+        size_t index;
+        index = offset + 0;
+        if (!r[index].isNull())
+        {
+            _id = std::make_shared<int32_t>(r[index].as<int32_t>());
+        }
+        index = offset + 1;
+        if (!r[index].isNull())
+        {
+            _message =
+                std::make_shared<std::string>(r[index].as<std::string>());
+        }
     }
 }
+
+Fortune::Fortune(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector) noexcept(false)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        LOG_ERROR << "Bad masquerading vector";
+        return;
+    }
+    if (!pMasqueradingVector[0].empty() &&
+        pJson.isMember(pMasqueradingVector[0]))
+    {
+        _dirtyFlag[0] = true;
+        if (!pJson[pMasqueradingVector[0]].isNull())
+        {
+            _id = std::make_shared<int32_t>(
+                (int32_t)pJson[pMasqueradingVector[0]].asInt64());
+        }
+    }
+    if (!pMasqueradingVector[1].empty() &&
+        pJson.isMember(pMasqueradingVector[1]))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson[pMasqueradingVector[1]].isNull())
+        {
+            _message = std::make_shared<std::string>(
+                pJson[pMasqueradingVector[1]].asString());
+        }
+    }
+}
+
+Fortune::Fortune(const Json::Value &pJson) noexcept(false)
+{
+    if (pJson.isMember("id"))
+    {
+        _dirtyFlag[0] = true;
+        if (!pJson["id"].isNull())
+        {
+            _id = std::make_shared<int32_t>((int32_t)pJson["id"].asInt64());
+        }
+    }
+    if (pJson.isMember("message"))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson["message"].isNull())
+        {
+            _message =
+                std::make_shared<std::string>(pJson["message"].asString());
+        }
+    }
+}
+
+void Fortune::updateByMasqueradedJson(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector) noexcept(false)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        LOG_ERROR << "Bad masquerading vector";
+        return;
+    }
+    if (!pMasqueradingVector[0].empty() &&
+        pJson.isMember(pMasqueradingVector[0]))
+    {
+        if (!pJson[pMasqueradingVector[0]].isNull())
+        {
+            _id = std::make_shared<int32_t>(
+                (int32_t)pJson[pMasqueradingVector[0]].asInt64());
+        }
+    }
+    if (!pMasqueradingVector[1].empty() &&
+        pJson.isMember(pMasqueradingVector[1]))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson[pMasqueradingVector[1]].isNull())
+        {
+            _message = std::make_shared<std::string>(
+                pJson[pMasqueradingVector[1]].asString());
+        }
+    }
+}
+
+void Fortune::updateByJson(const Json::Value &pJson) noexcept(false)
+{
+    if (pJson.isMember("id"))
+    {
+        if (!pJson["id"].isNull())
+        {
+            _id = std::make_shared<int32_t>((int32_t)pJson["id"].asInt64());
+        }
+    }
+    if (pJson.isMember("message"))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson["message"].isNull())
+        {
+            _message =
+                std::make_shared<std::string>(pJson["message"].asString());
+        }
+    }
+}
+
 const int32_t &Fortune::getValueOfId() const noexcept
 {
     const static int32_t defaultValue = int32_t();
@@ -49,9 +176,9 @@ const std::shared_ptr<int32_t> &Fortune::getId() const noexcept
 {
     return _id;
 }
-void Fortune::setId(const int32_t &id) noexcept
+void Fortune::setId(const int32_t &pId) noexcept
 {
-    _id = std::make_shared<int32_t>(id);
+    _id = std::make_shared<int32_t>(pId);
     _dirtyFlag[0] = true;
 }
 
@@ -72,14 +199,14 @@ const std::shared_ptr<std::string> &Fortune::getMessage() const noexcept
 {
     return _message;
 }
-void Fortune::setMessage(const std::string &message) noexcept
+void Fortune::setMessage(const std::string &pMessage) noexcept
 {
-    _message = std::make_shared<std::string>(message);
+    _message = std::make_shared<std::string>(pMessage);
     _dirtyFlag[1] = true;
 }
-void Fortune::setMessage(std::string &&message) noexcept
+void Fortune::setMessage(std::string &&pMessage) noexcept
 {
-    _message = std::make_shared<std::string>(std::move(message));
+    _message = std::make_shared<std::string>(std::move(pMessage));
     _dirtyFlag[1] = true;
 }
 
@@ -95,21 +222,27 @@ const std::vector<std::string> &Fortune::insertColumns() noexcept
 
 void Fortune::outputArgs(drogon::orm::internal::SqlBinder &binder) const
 {
-    if (getId())
-    {
-        binder << getValueOfId();
-    }
-    else
-    {
-        binder << nullptr;
-    }
-    if (getMessage())
+    if (_dirtyFlag[0])
     {
-        binder << getValueOfMessage();
+        if (getId())
+        {
+            binder << getValueOfId();
+        }
+        else
+        {
+            binder << nullptr;
+        }
     }
-    else
+    if (_dirtyFlag[1])
     {
-        binder << nullptr;
+        if (getMessage())
+        {
+            binder << getValueOfMessage();
+        }
+        else
+        {
+            binder << nullptr;
+        }
     }
 }
 
@@ -172,3 +305,234 @@ Json::Value Fortune::toJson() const
     }
     return ret;
 }
+
+Json::Value Fortune::toMasqueradedJson(
+    const std::vector<std::string> &pMasqueradingVector) const
+{
+    Json::Value ret;
+    if (pMasqueradingVector.size() == 2)
+    {
+        if (!pMasqueradingVector[0].empty())
+        {
+            if (getId())
+            {
+                ret[pMasqueradingVector[0]] = getValueOfId();
+            }
+            else
+            {
+                ret[pMasqueradingVector[0]] = Json::Value();
+            }
+        }
+        if (!pMasqueradingVector[1].empty())
+        {
+            if (getMessage())
+            {
+                ret[pMasqueradingVector[1]] = getValueOfMessage();
+            }
+            else
+            {
+                ret[pMasqueradingVector[1]] = Json::Value();
+            }
+        }
+        return ret;
+    }
+    LOG_ERROR << "Masquerade failed";
+    if (getId())
+    {
+        ret["id"] = getValueOfId();
+    }
+    else
+    {
+        ret["id"] = Json::Value();
+    }
+    if (getMessage())
+    {
+        ret["message"] = getValueOfMessage();
+    }
+    else
+    {
+        ret["message"] = Json::Value();
+    }
+    return ret;
+}
+
+bool Fortune::validateJsonForCreation(const Json::Value &pJson,
+                                      std::string &err)
+{
+    if (pJson.isMember("id"))
+    {
+        if (!validJsonOfField(0, "id", pJson["id"], err, true))
+            return false;
+    }
+    else
+    {
+        err = "The id column cannot be null";
+        return false;
+    }
+    if (pJson.isMember("message"))
+    {
+        if (!validJsonOfField(1, "message", pJson["message"], err, true))
+            return false;
+    }
+    else
+    {
+        err = "The message column cannot be null";
+        return false;
+    }
+    return true;
+}
+bool Fortune::validateMasqueradedJsonForCreation(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector,
+    std::string &err)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        err = "Bad masquerading vector";
+        return false;
+    }
+    if (!pMasqueradingVector[0].empty())
+    {
+        if (pJson.isMember(pMasqueradingVector[0]))
+        {
+            if (!validJsonOfField(0,
+                                  pMasqueradingVector[0],
+                                  pJson[pMasqueradingVector[0]],
+                                  err,
+                                  true))
+                return false;
+        }
+        else
+        {
+            err = "The " + pMasqueradingVector[0] + " column cannot be null";
+            return false;
+        }
+    }
+    if (!pMasqueradingVector[1].empty())
+    {
+        if (pJson.isMember(pMasqueradingVector[1]))
+        {
+            if (!validJsonOfField(1,
+                                  pMasqueradingVector[1],
+                                  pJson[pMasqueradingVector[1]],
+                                  err,
+                                  true))
+                return false;
+        }
+        else
+        {
+            err = "The " + pMasqueradingVector[1] + " column cannot be null";
+            return false;
+        }
+    }
+    return true;
+}
+bool Fortune::validateJsonForUpdate(const Json::Value &pJson, std::string &err)
+{
+    if (pJson.isMember("id"))
+    {
+        if (!validJsonOfField(0, "id", pJson["id"], err, false))
+            return false;
+    }
+    else
+    {
+        err =
+            "The value of primary key must be set in the json object for "
+            "update";
+        return false;
+    }
+    if (pJson.isMember("message"))
+    {
+        if (!validJsonOfField(1, "message", pJson["message"], err, false))
+            return false;
+    }
+    return true;
+}
+bool Fortune::validateMasqueradedJsonForUpdate(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector,
+    std::string &err)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        err = "Bad masquerading vector";
+        return false;
+    }
+    if (!pMasqueradingVector[0].empty() &&
+        pJson.isMember(pMasqueradingVector[0]))
+    {
+        if (!validJsonOfField(0,
+                              pMasqueradingVector[0],
+                              pJson[pMasqueradingVector[0]],
+                              err,
+                              false))
+            return false;
+    }
+    else
+    {
+        err =
+            "The value of primary key must be set in the json object for "
+            "update";
+        return false;
+    }
+    if (!pMasqueradingVector[1].empty() &&
+        pJson.isMember(pMasqueradingVector[1]))
+    {
+        if (!validJsonOfField(1,
+                              pMasqueradingVector[1],
+                              pJson[pMasqueradingVector[1]],
+                              err,
+                              false))
+            return false;
+    }
+    return true;
+}
+bool Fortune::validJsonOfField(size_t index,
+                               const std::string &fieldName,
+                               const Json::Value &pJson,
+                               std::string &err,
+                               bool isForCreation)
+{
+    switch (index)
+    {
+        case 0:
+            if (pJson.isNull())
+            {
+                err = "The " + fieldName + " column cannot be null";
+                return false;
+            }
+            if (!pJson.isInt())
+            {
+                err = "Type error in the " + fieldName + " field";
+                return false;
+            }
+            break;
+        case 1:
+            if (pJson.isNull())
+            {
+                err = "The " + fieldName + " column cannot be null";
+                return false;
+            }
+            if (!pJson.isString())
+            {
+                err = "Type error in the " + fieldName + " field";
+                return false;
+            }
+            // asString().length() creates a string object, is there any better
+            // way to validate the length?
+            if (pJson.isString() && pJson.asString().length() > 2048)
+            {
+                err = "String length exceeds limit for the " + fieldName +
+                      " field (the maximum value is 2048)";
+                return false;
+            }
+
+            break;
+
+        default:
+            err = "Internal error in the server";
+            return false;
+            break;
+    }
+    return true;
+}

+ 122 - 7
frameworks/C++/drogon/drogon_benchmark/models/Fortune.h

@@ -12,6 +12,7 @@
 #include <drogon/orm/SqlBinder.h>
 #include <drogon/orm/Mapper.h>
 #include <trantor/utils/Date.h>
+#include <trantor/utils/Logger.h>
 #include <json/json.h>
 #include <string>
 #include <memory>
@@ -31,8 +32,8 @@ class Fortune
   public:
     struct Cols
     {
-        static const std::string id;
-        static const std::string message;
+        static const std::string _id;
+        static const std::string _message;
     };
 
     const static int primaryKeyNumber;
@@ -41,9 +42,56 @@ class Fortune
     const static std::string primaryKeyName;
     typedef int32_t PrimaryKeyType;
     const PrimaryKeyType &getPrimaryKey() const;
-    explicit Fortune(const Row &r) noexcept;
+
+    /**
+     * @brief constructor
+     * @param r One row of records in the SQL query result.
+     * @param indexOffset Set the offset to -1 to access all columns by column
+     * names, otherwise access all columns by offsets.
+     * @note If the SQL is not a style of 'select * from table_name ...' (select
+     * all columns by an asterisk), please set the offset to -1.
+     */
+    explicit Fortune(const Row &r, const ssize_t indexOffset = 0) noexcept;
+
+    /**
+     * @brief constructor
+     * @param pJson The json object to construct a new instance.
+     */
+    explicit Fortune(const Json::Value &pJson) noexcept(false);
+
+    /**
+     * @brief constructor
+     * @param pJson The json object to construct a new instance.
+     * @param pMasqueradingVector The aliases of table columns.
+     */
+    Fortune(
+        const Json::Value &pJson,
+        const std::vector<std::string> &pMasqueradingVector) noexcept(false);
+
     Fortune() = default;
 
+    void updateByJson(const Json::Value &pJson) noexcept(false);
+    void updateByMasqueradedJson(
+        const Json::Value &pJson,
+        const std::vector<std::string> &pMasqueradingVector) noexcept(false);
+    static bool validateJsonForCreation(const Json::Value &pJson,
+                                        std::string &err);
+    static bool validateMasqueradedJsonForCreation(
+        const Json::Value &,
+        const std::vector<std::string> &pMasqueradingVector,
+        std::string &err);
+    static bool validateJsonForUpdate(const Json::Value &pJson,
+                                      std::string &err);
+    static bool validateMasqueradedJsonForUpdate(
+        const Json::Value &,
+        const std::vector<std::string> &pMasqueradingVector,
+        std::string &err);
+    static bool validJsonOfField(size_t index,
+                                 const std::string &fieldName,
+                                 const Json::Value &pJson,
+                                 std::string &err,
+                                 bool isForCreation);
+
     /**  For column id  */
     /// Get the value of the column id, returns the default value if the column
     /// is null
@@ -52,7 +100,7 @@ class Fortune
     /// empty shared_ptr object if the column is null
     const std::shared_ptr<int32_t> &getId() const noexcept;
     /// Set the value of the column id
-    void setId(const int32_t &id) noexcept;
+    void setId(const int32_t &pId) noexcept;
 
     /**  For column message  */
     /// Get the value of the column message, returns the default value if the
@@ -62,8 +110,8 @@ class Fortune
     /// empty shared_ptr object if the column is null
     const std::shared_ptr<std::string> &getMessage() const noexcept;
     /// Set the value of the column message
-    void setMessage(const std::string &message) noexcept;
-    void setMessage(std::string &&message) noexcept;
+    void setMessage(const std::string &pMessage) noexcept;
+    void setMessage(std::string &&pMessage) noexcept;
 
     static size_t getColumnNumber() noexcept
     {
@@ -72,6 +120,8 @@ class Fortune
     static const std::string &getColumnName(size_t index) noexcept(false);
 
     Json::Value toJson() const;
+    Json::Value toMasqueradedJson(
+        const std::vector<std::string> &pMasqueradingVector) const;
 
   private:
     friend Mapper<Fortune>;
@@ -95,7 +145,72 @@ class Fortune
     };
     static const std::vector<MetaData> _metaData;
     bool _dirtyFlag[2] = {false};
-};
 
+  public:
+    static const std::string &sqlForFindingByPrimaryKey()
+    {
+        static const std::string sql =
+            "select * from " + tableName + " where id = $1";
+        return sql;
+    }
+
+    static const std::string &sqlForDeletingByPrimaryKey()
+    {
+        static const std::string sql =
+            "delete from " + tableName + " where id = $1";
+        return sql;
+    }
+    std::string sqlForInserting(bool &needSelection) const
+    {
+        std::string sql = "insert into " + tableName + " (";
+        size_t parametersCount = 0;
+        needSelection = false;
+        if (_dirtyFlag[0])
+        {
+            sql += "id,";
+            ++parametersCount;
+        }
+        if (_dirtyFlag[1])
+        {
+            sql += "message,";
+            ++parametersCount;
+        }
+        if (parametersCount > 0)
+        {
+            sql[sql.length() - 1] = ')';
+            sql += " values (";
+        }
+        else
+            sql += ") values (";
+
+        int placeholder = 1;
+        char placeholderStr[64];
+        size_t n = 0;
+        if (_dirtyFlag[0])
+        {
+            n = sprintf(placeholderStr, "$%d,", placeholder++);
+            sql.append(placeholderStr, n);
+        }
+        if (_dirtyFlag[1])
+        {
+            n = sprintf(placeholderStr, "$%d,", placeholder++);
+            sql.append(placeholderStr, n);
+        }
+        if (parametersCount > 0)
+        {
+            sql.resize(sql.length() - 1);
+        }
+        if (needSelection)
+        {
+            sql.append(") returning *");
+        }
+        else
+        {
+            sql.append(1, ')');
+        }
+        LOG_TRACE << sql;
+        return sql;
+    }
+};
 }  // namespace hello_world
 }  // namespace drogon_model

+ 369 - 24
frameworks/C++/drogon/drogon_benchmark/models/World.cc

@@ -12,8 +12,8 @@
 using namespace drogon;
 using namespace drogon_model::hello_world;
 
-const std::string World::Cols::id = "id";
-const std::string World::Cols::randomnumber = "randomnumber";
+const std::string World::Cols::_id = "id";
+const std::string World::Cols::_randomnumber = "randomnumber";
 const std::string World::primaryKeyName = "id";
 const bool World::hasPrimaryKey = true;
 const std::string World::tableName = "world";
@@ -26,18 +26,144 @@ const std::string &World::getColumnName(size_t index) noexcept(false)
     assert(index < _metaData.size());
     return _metaData[index]._colName;
 }
-World::World(const Row &r) noexcept
+World::World(const Row &r, const ssize_t indexOffset) noexcept
 {
-    if (!r["id"].isNull())
+    if (indexOffset < 0)
     {
-        _id = std::make_shared<int32_t>(r["id"].as<int32_t>());
+        if (!r["id"].isNull())
+        {
+            _id = std::make_shared<int32_t>(r["id"].as<int32_t>());
+        }
+        if (!r["randomnumber"].isNull())
+        {
+            _randomnumber =
+                std::make_shared<int32_t>(r["randomnumber"].as<int32_t>());
+        }
+    }
+    else
+    {
+        size_t offset = (size_t)indexOffset;
+        if (offset + 2 > r.size())
+        {
+            LOG_FATAL << "Invalid SQL result for this model";
+            return;
+        }
+        size_t index;
+        index = offset + 0;
+        if (!r[index].isNull())
+        {
+            _id = std::make_shared<int32_t>(r[index].as<int32_t>());
+        }
+        index = offset + 1;
+        if (!r[index].isNull())
+        {
+            _randomnumber = std::make_shared<int32_t>(r[index].as<int32_t>());
+        }
+    }
+}
+
+World::World(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector) noexcept(false)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        LOG_ERROR << "Bad masquerading vector";
+        return;
+    }
+    if (!pMasqueradingVector[0].empty() &&
+        pJson.isMember(pMasqueradingVector[0]))
+    {
+        _dirtyFlag[0] = true;
+        if (!pJson[pMasqueradingVector[0]].isNull())
+        {
+            _id = std::make_shared<int32_t>(
+                (int32_t)pJson[pMasqueradingVector[0]].asInt64());
+        }
+    }
+    if (!pMasqueradingVector[1].empty() &&
+        pJson.isMember(pMasqueradingVector[1]))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson[pMasqueradingVector[1]].isNull())
+        {
+            _randomnumber = std::make_shared<int32_t>(
+                (int32_t)pJson[pMasqueradingVector[1]].asInt64());
+        }
+    }
+}
+
+World::World(const Json::Value &pJson) noexcept(false)
+{
+    if (pJson.isMember("id"))
+    {
+        _dirtyFlag[0] = true;
+        if (!pJson["id"].isNull())
+        {
+            _id = std::make_shared<int32_t>((int32_t)pJson["id"].asInt64());
+        }
+    }
+    if (pJson.isMember("randomnumber"))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson["randomnumber"].isNull())
+        {
+            _randomnumber = std::make_shared<int32_t>(
+                (int32_t)pJson["randomnumber"].asInt64());
+        }
+    }
+}
+
+void World::updateByMasqueradedJson(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector) noexcept(false)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        LOG_ERROR << "Bad masquerading vector";
+        return;
     }
-    if (!r["randomnumber"].isNull())
+    if (!pMasqueradingVector[0].empty() &&
+        pJson.isMember(pMasqueradingVector[0]))
     {
-        _randomnumber =
-            std::make_shared<int32_t>(r["randomnumber"].as<int32_t>());
+        if (!pJson[pMasqueradingVector[0]].isNull())
+        {
+            _id = std::make_shared<int32_t>(
+                (int32_t)pJson[pMasqueradingVector[0]].asInt64());
+        }
+    }
+    if (!pMasqueradingVector[1].empty() &&
+        pJson.isMember(pMasqueradingVector[1]))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson[pMasqueradingVector[1]].isNull())
+        {
+            _randomnumber = std::make_shared<int32_t>(
+                (int32_t)pJson[pMasqueradingVector[1]].asInt64());
+        }
     }
 }
+
+void World::updateByJson(const Json::Value &pJson) noexcept(false)
+{
+    if (pJson.isMember("id"))
+    {
+        if (!pJson["id"].isNull())
+        {
+            _id = std::make_shared<int32_t>((int32_t)pJson["id"].asInt64());
+        }
+    }
+    if (pJson.isMember("randomnumber"))
+    {
+        _dirtyFlag[1] = true;
+        if (!pJson["randomnumber"].isNull())
+        {
+            _randomnumber = std::make_shared<int32_t>(
+                (int32_t)pJson["randomnumber"].asInt64());
+        }
+    }
+}
+
 const int32_t &World::getValueOfId() const noexcept
 {
     const static int32_t defaultValue = int32_t();
@@ -49,9 +175,9 @@ const std::shared_ptr<int32_t> &World::getId() const noexcept
 {
     return _id;
 }
-void World::setId(const int32_t &id) noexcept
+void World::setId(const int32_t &pId) noexcept
 {
-    _id = std::make_shared<int32_t>(id);
+    _id = std::make_shared<int32_t>(pId);
     _dirtyFlag[0] = true;
 }
 
@@ -72,9 +198,9 @@ const std::shared_ptr<int32_t> &World::getRandomnumber() const noexcept
 {
     return _randomnumber;
 }
-void World::setRandomnumber(const int32_t &randomnumber) noexcept
+void World::setRandomnumber(const int32_t &pRandomnumber) noexcept
 {
-    _randomnumber = std::make_shared<int32_t>(randomnumber);
+    _randomnumber = std::make_shared<int32_t>(pRandomnumber);
     _dirtyFlag[1] = true;
 }
 
@@ -90,21 +216,27 @@ const std::vector<std::string> &World::insertColumns() noexcept
 
 void World::outputArgs(drogon::orm::internal::SqlBinder &binder) const
 {
-    if (getId())
-    {
-        binder << getValueOfId();
-    }
-    else
-    {
-        binder << nullptr;
-    }
-    if (getRandomnumber())
+    if (_dirtyFlag[0])
     {
-        binder << getValueOfRandomnumber();
+        if (getId())
+        {
+            binder << getValueOfId();
+        }
+        else
+        {
+            binder << nullptr;
+        }
     }
-    else
+    if (_dirtyFlag[1])
     {
-        binder << nullptr;
+        if (getRandomnumber())
+        {
+            binder << getValueOfRandomnumber();
+        }
+        else
+        {
+            binder << nullptr;
+        }
     }
 }
 
@@ -167,3 +299,216 @@ Json::Value World::toJson() const
     }
     return ret;
 }
+
+Json::Value World::toMasqueradedJson(
+    const std::vector<std::string> &pMasqueradingVector) const
+{
+    Json::Value ret;
+    if (pMasqueradingVector.size() == 2)
+    {
+        if (!pMasqueradingVector[0].empty())
+        {
+            if (getId())
+            {
+                ret[pMasqueradingVector[0]] = getValueOfId();
+            }
+            else
+            {
+                ret[pMasqueradingVector[0]] = Json::Value();
+            }
+        }
+        if (!pMasqueradingVector[1].empty())
+        {
+            if (getRandomnumber())
+            {
+                ret[pMasqueradingVector[1]] = getValueOfRandomnumber();
+            }
+            else
+            {
+                ret[pMasqueradingVector[1]] = Json::Value();
+            }
+        }
+        return ret;
+    }
+    LOG_ERROR << "Masquerade failed";
+    if (getId())
+    {
+        ret["id"] = getValueOfId();
+    }
+    else
+    {
+        ret["id"] = Json::Value();
+    }
+    if (getRandomnumber())
+    {
+        ret["randomnumber"] = getValueOfRandomnumber();
+    }
+    else
+    {
+        ret["randomnumber"] = Json::Value();
+    }
+    return ret;
+}
+
+bool World::validateJsonForCreation(const Json::Value &pJson, std::string &err)
+{
+    if (pJson.isMember("id"))
+    {
+        if (!validJsonOfField(0, "id", pJson["id"], err, true))
+            return false;
+    }
+    else
+    {
+        err = "The id column cannot be null";
+        return false;
+    }
+    if (pJson.isMember("randomnumber"))
+    {
+        if (!validJsonOfField(
+                1, "randomnumber", pJson["randomnumber"], err, true))
+            return false;
+    }
+    return true;
+}
+bool World::validateMasqueradedJsonForCreation(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector,
+    std::string &err)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        err = "Bad masquerading vector";
+        return false;
+    }
+    if (!pMasqueradingVector[0].empty())
+    {
+        if (pJson.isMember(pMasqueradingVector[0]))
+        {
+            if (!validJsonOfField(0,
+                                  pMasqueradingVector[0],
+                                  pJson[pMasqueradingVector[0]],
+                                  err,
+                                  true))
+                return false;
+        }
+        else
+        {
+            err = "The " + pMasqueradingVector[0] + " column cannot be null";
+            return false;
+        }
+    }
+    if (!pMasqueradingVector[1].empty())
+    {
+        if (pJson.isMember(pMasqueradingVector[1]))
+        {
+            if (!validJsonOfField(1,
+                                  pMasqueradingVector[1],
+                                  pJson[pMasqueradingVector[1]],
+                                  err,
+                                  true))
+                return false;
+        }
+    }
+    return true;
+}
+bool World::validateJsonForUpdate(const Json::Value &pJson, std::string &err)
+{
+    if (pJson.isMember("id"))
+    {
+        if (!validJsonOfField(0, "id", pJson["id"], err, false))
+            return false;
+    }
+    else
+    {
+        err =
+            "The value of primary key must be set in the json object for "
+            "update";
+        return false;
+    }
+    if (pJson.isMember("randomnumber"))
+    {
+        if (!validJsonOfField(
+                1, "randomnumber", pJson["randomnumber"], err, false))
+            return false;
+    }
+    return true;
+}
+bool World::validateMasqueradedJsonForUpdate(
+    const Json::Value &pJson,
+    const std::vector<std::string> &pMasqueradingVector,
+    std::string &err)
+{
+    if (pMasqueradingVector.size() != 2)
+    {
+        err = "Bad masquerading vector";
+        return false;
+    }
+    if (!pMasqueradingVector[0].empty() &&
+        pJson.isMember(pMasqueradingVector[0]))
+    {
+        if (!validJsonOfField(0,
+                              pMasqueradingVector[0],
+                              pJson[pMasqueradingVector[0]],
+                              err,
+                              false))
+            return false;
+    }
+    else
+    {
+        err =
+            "The value of primary key must be set in the json object for "
+            "update";
+        return false;
+    }
+    if (!pMasqueradingVector[1].empty() &&
+        pJson.isMember(pMasqueradingVector[1]))
+    {
+        if (!validJsonOfField(1,
+                              pMasqueradingVector[1],
+                              pJson[pMasqueradingVector[1]],
+                              err,
+                              false))
+            return false;
+    }
+    return true;
+}
+bool World::validJsonOfField(size_t index,
+                             const std::string &fieldName,
+                             const Json::Value &pJson,
+                             std::string &err,
+                             bool isForCreation)
+{
+    switch (index)
+    {
+        case 0:
+            if (pJson.isNull())
+            {
+                err = "The " + fieldName + " column cannot be null";
+                return false;
+            }
+            if (!pJson.isInt())
+            {
+                err = "Type error in the " + fieldName + " field";
+                return false;
+            }
+            break;
+        case 1:
+            if (pJson.isNull())
+            {
+                err = "The " + fieldName + " column cannot be null";
+                return false;
+            }
+            if (!pJson.isInt())
+            {
+                err = "Type error in the " + fieldName + " field";
+                return false;
+            }
+            break;
+
+        default:
+            err = "Internal error in the server";
+            return false;
+            break;
+    }
+    return true;
+}

+ 125 - 6
frameworks/C++/drogon/drogon_benchmark/models/World.h

@@ -12,6 +12,7 @@
 #include <drogon/orm/SqlBinder.h>
 #include <drogon/orm/Mapper.h>
 #include <trantor/utils/Date.h>
+#include <trantor/utils/Logger.h>
 #include <json/json.h>
 #include <string>
 #include <memory>
@@ -31,8 +32,8 @@ class World
   public:
     struct Cols
     {
-        static const std::string id;
-        static const std::string randomnumber;
+        static const std::string _id;
+        static const std::string _randomnumber;
     };
 
     const static int primaryKeyNumber;
@@ -41,9 +42,55 @@ class World
     const static std::string primaryKeyName;
     typedef int32_t PrimaryKeyType;
     const PrimaryKeyType &getPrimaryKey() const;
-    explicit World(const Row &r) noexcept;
+
+    /**
+     * @brief constructor
+     * @param r One row of records in the SQL query result.
+     * @param indexOffset Set the offset to -1 to access all columns by column
+     * names, otherwise access all columns by offsets.
+     * @note If the SQL is not a style of 'select * from table_name ...' (select
+     * all columns by an asterisk), please set the offset to -1.
+     */
+    explicit World(const Row &r, const ssize_t indexOffset = 0) noexcept;
+
+    /**
+     * @brief constructor
+     * @param pJson The json object to construct a new instance.
+     */
+    explicit World(const Json::Value &pJson) noexcept(false);
+
+    /**
+     * @brief constructor
+     * @param pJson The json object to construct a new instance.
+     * @param pMasqueradingVector The aliases of table columns.
+     */
+    World(const Json::Value &pJson,
+          const std::vector<std::string> &pMasqueradingVector) noexcept(false);
+
     World() = default;
 
+    void updateByJson(const Json::Value &pJson) noexcept(false);
+    void updateByMasqueradedJson(
+        const Json::Value &pJson,
+        const std::vector<std::string> &pMasqueradingVector) noexcept(false);
+    static bool validateJsonForCreation(const Json::Value &pJson,
+                                        std::string &err);
+    static bool validateMasqueradedJsonForCreation(
+        const Json::Value &,
+        const std::vector<std::string> &pMasqueradingVector,
+        std::string &err);
+    static bool validateJsonForUpdate(const Json::Value &pJson,
+                                      std::string &err);
+    static bool validateMasqueradedJsonForUpdate(
+        const Json::Value &,
+        const std::vector<std::string> &pMasqueradingVector,
+        std::string &err);
+    static bool validJsonOfField(size_t index,
+                                 const std::string &fieldName,
+                                 const Json::Value &pJson,
+                                 std::string &err,
+                                 bool isForCreation);
+
     /**  For column id  */
     /// Get the value of the column id, returns the default value if the column
     /// is null
@@ -52,7 +99,7 @@ class World
     /// empty shared_ptr object if the column is null
     const std::shared_ptr<int32_t> &getId() const noexcept;
     /// Set the value of the column id
-    void setId(const int32_t &id) noexcept;
+    void setId(const int32_t &pId) noexcept;
 
     /**  For column randomnumber  */
     /// Get the value of the column randomnumber, returns the default value if
@@ -62,7 +109,7 @@ class World
     /// empty shared_ptr object if the column is null
     const std::shared_ptr<int32_t> &getRandomnumber() const noexcept;
     /// Set the value of the column randomnumber
-    void setRandomnumber(const int32_t &randomnumber) noexcept;
+    void setRandomnumber(const int32_t &pRandomnumber) noexcept;
 
     static size_t getColumnNumber() noexcept
     {
@@ -71,6 +118,8 @@ class World
     static const std::string &getColumnName(size_t index) noexcept(false);
 
     Json::Value toJson() const;
+    Json::Value toMasqueradedJson(
+        const std::vector<std::string> &pMasqueradingVector) const;
 
   private:
     friend Mapper<World>;
@@ -94,7 +143,77 @@ class World
     };
     static const std::vector<MetaData> _metaData;
     bool _dirtyFlag[2] = {false};
-};
 
+  public:
+    static const std::string &sqlForFindingByPrimaryKey()
+    {
+        static const std::string sql =
+            "select * from " + tableName + " where id = $1";
+        return sql;
+    }
+
+    static const std::string &sqlForDeletingByPrimaryKey()
+    {
+        static const std::string sql =
+            "delete from " + tableName + " where id = $1";
+        return sql;
+    }
+    std::string sqlForInserting(bool &needSelection) const
+    {
+        std::string sql = "insert into " + tableName + " (";
+        size_t parametersCount = 0;
+        needSelection = false;
+        if (_dirtyFlag[0])
+        {
+            sql += "id,";
+            ++parametersCount;
+        }
+        sql += "randomnumber,";
+        ++parametersCount;
+        if (!_dirtyFlag[1])
+        {
+            needSelection = true;
+        }
+        if (parametersCount > 0)
+        {
+            sql[sql.length() - 1] = ')';
+            sql += " values (";
+        }
+        else
+            sql += ") values (";
+
+        int placeholder = 1;
+        char placeholderStr[64];
+        size_t n = 0;
+        if (_dirtyFlag[0])
+        {
+            n = sprintf(placeholderStr, "$%d,", placeholder++);
+            sql.append(placeholderStr, n);
+        }
+        if (_dirtyFlag[1])
+        {
+            n = sprintf(placeholderStr, "$%d,", placeholder++);
+            sql.append(placeholderStr, n);
+        }
+        else
+        {
+            sql += "default,";
+        }
+        if (parametersCount > 0)
+        {
+            sql.resize(sql.length() - 1);
+        }
+        if (needSelection)
+        {
+            sql.append(") returning *");
+        }
+        else
+        {
+            sql.append(1, ')');
+        }
+        LOG_TRACE << sql;
+        return sql;
+    }
+};
 }  // namespace hello_world
 }  // namespace drogon_model