model.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #ifndef MODEL_HH
  2. #define MODEL_HH
  3. #include "metaclassparser.h"
  4. #include "modelbasicoperation.h"
  5. #include "sqlquery.h"
  6. #include <QDateTime>
  7. #include <QDebug>
  8. #include <QMetaObject>
  9. #include <QMetaProperty>
  10. #include <QObject>
  11. #include <memory>
  12. CWF_BEGIN_NAMESPACE
  13. /**
  14. * @brief The Model class implements basic ORM features and should be used as base class for every model (or entity).
  15. *
  16. * The class allows any derived model to be saved, retrieved or deleted from the database in very direct fashion
  17. * (see the example below). By default, the class contains three properties that should not be overriden:
  18. * - id : The id of the model. Its value is -1 when it the model is created or when the model could not be loaded from the database.
  19. * - createdDateTime : The date at which the model was first created.
  20. * - lastModifiedDateTime : The latest date at which the model was modified.
  21. * These properties will be added to every model.
  22. *
  23. * Each model is represented by a table in the database which is identical to the name of the model.
  24. *
  25. * A typical model is defined as:
  26. *
  27. * ```cpp
  28. * class UserModel : public Model
  29. * {
  30. * Q_OBJECT
  31. *
  32. * Q_PROPERTY(QString email MEMBER email NOTIFY emailChanged)
  33. *
  34. * public:
  35. * UserModel() : Model("user") // Name of the model and database table
  36. * {
  37. * }
  38. * ~UserModel() override;
  39. *
  40. * signals:
  41. * void emailChanged();
  42. *
  43. * private:
  44. * QString email;
  45. * }
  46. * ```
  47. *
  48. * And can be used in a controller with:
  49. * ```cpp
  50. * // Create an empty instance of your model
  51. * MyModel myModel;
  52. *
  53. * // Set some values
  54. * myModel.setEmail(myEmail);
  55. *
  56. * // Save it in the database
  57. * myModel.save();
  58. *
  59. * // Get the database id of the model just persisted.
  60. * int myModelId = myModel.getId();
  61. *
  62. * // Create another instance
  63. * MyModel myModel2;
  64. *
  65. * // Load the first instance data from the database
  66. * myModel2.build(myModelId); // We use the id of the first instance
  67. *
  68. * // Check the object was loaded
  69. * if(!myModel2.getWasBuild() )
  70. * {
  71. * // Error: it was not loaded for some reason...
  72. * }
  73. *
  74. * // Delete the object from the database
  75. * myModel2.remove();
  76. * ```
  77. */
  78. class CPPWEBFRAMEWORKSHARED_EXPORT Model : public QObject
  79. {
  80. Q_OBJECT
  81. protected:
  82. ModelBasicOperation basicOperation;
  83. private:
  84. Q_PROPERTY(qint64 id MEMBER id NOTIFY idChanged)
  85. Q_PROPERTY(QString createdDateTime MEMBER createdDateTime NOTIFY createdDateTimeChanged)
  86. Q_PROPERTY(
  87. QString lastModifiedDateTime MEMBER lastModifiedDateTime NOTIFY lastModifiedDateTimeChanged)
  88. /**
  89. * @brief id The database id of the model
  90. * The id is set to -1 by default. It may change if the model was populated with data from the database (the id will become the one
  91. * of the entity stored in the database) or if a user manually set the variable before.
  92. */
  93. QString name; ///< @brief name The name of the model
  94. QString dtFormat = "dd/MM/yyyy hh:mm:ss.zzz"; ///< @brief Format of the date used in this class
  95. QString createdDateTime; ///< @brief First save in the database date
  96. QString lastModifiedDateTime; ///< @brief Last modified and persisted date
  97. qint64 id = -1;
  98. qint64 version; ///< @brief The version of the table (database side)
  99. bool built = false; ///< @brief Was the model instance populated with data ?
  100. private:
  101. void verifyDbTableExist(); ///< @brief Check the database contains table corresponding to this model. Also create or update the table if needed.
  102. void verifyDbFields(); ///< @brief Check the database table contains all required fields (columns). If not, create them.
  103. public:
  104. /**
  105. * @brief Constructor
  106. */
  107. explicit Model(SqlDatabaseStorage &connection, const QString &name)
  108. : basicOperation(connection)
  109. , name(name)
  110. {}
  111. /**
  112. * @brief Destructor
  113. */
  114. virtual ~Model() = default;
  115. /**
  116. * @brief updateDB Will create or update the database schema to match the model class.
  117. * This allows to create a working table from scratch or to update one. Note that a table update can add new
  118. * fields (Qt properties in the model code) but cannot remove any. Therefore, a developer should only add new
  119. * properties to a model and never remove one.
  120. */
  121. void updateDB();
  122. /**
  123. * @brief build Populate the model with data from the database.
  124. * @param id The id of the data to be used to populate the model. id = -1 indicates an insertion. id != -1 indicates an update.
  125. */
  126. inline void build(const qint64 &id = -1)
  127. {
  128. build({{"id", QVariant::fromValue(this->id = id)}});
  129. }
  130. /**
  131. * @brief build Populate the model with data from the database.
  132. * @param selectCondition A map ([propertyName] = propertyValue) of property values
  133. * used to choose which data to insert in the model.
  134. *
  135. * The first entry of database table that matchs all the property values will be used to populate the model.
  136. */
  137. void build(const QMap<QString, QVariant> &selectCondition);
  138. /**
  139. * @brief buildFromJson Populate a model from json data
  140. * @param json The data used to populate the model instance
  141. * @param withTableNamePrefix Are the date properties prefixed with the name of this model db table ? This is false by default.
  142. */
  143. void buildFromJson(const QJsonObject &json, bool withTableNamePrefix = false);
  144. /**
  145. * @brief save Persist the model in the database
  146. * @return Bool: Was the model correctly persisted ?
  147. */
  148. bool save();
  149. /**
  150. * @brief remove Delete the model from the database
  151. * @return Bool: Was the data removed without error ?
  152. */
  153. inline bool remove() { return basicOperation.remove(getTableName(), id); }
  154. /**
  155. * @brief setCreatedDt Manually set the creation date
  156. * @param dt Date of the model first save into the database.
  157. */
  158. void setCreatedDt(const QDateTime &dt);
  159. /**
  160. * @brief setLastModifiedDt Set the last date at which the model was persisted in the database.
  161. * @param dt The date to be used.
  162. */
  163. void setLastModifiedDt(const QDateTime &dt);
  164. /**
  165. * @brief setWasBuild Set the "was build" flag that indicate if a model instance was correctly populated (build) by data.
  166. * @param b The flag.
  167. */
  168. inline void setWasBuild(bool b) { built = b; }
  169. /**
  170. * @brief getWasBuild Get the value of the "was build" flag.
  171. * @return Bool: Was the model instance populated by data from the database ?
  172. */
  173. inline bool getWasBuild() const { return built; }
  174. /**
  175. * @brief getId Get the id of the model
  176. * @return qint64: The id of the model
  177. */
  178. inline qint64 getId() const { return id; }
  179. /**
  180. * @brief getCreatedDt Get the creation date of the model
  181. * @return QDateTime: Creation date
  182. */
  183. inline QDateTime getCreatedDt() const
  184. {
  185. return QDateTime::fromString(createdDateTime, dtFormat);
  186. }
  187. /**
  188. * @brief getCreatedDtStr Get the creation date as a string
  189. * @return QString: Creation date as a string
  190. */
  191. inline QString getCreatedDtStr() const { return createdDateTime; }
  192. /**
  193. * @brief getLastModifiedDt Get the last date at which the model was modified and persisted in the database
  194. * @return QDateTime: Last modified and persisted date
  195. */
  196. inline QDateTime getLastModifiedDt() const
  197. {
  198. return QDateTime::fromString(lastModifiedDateTime, dtFormat);
  199. }
  200. /**
  201. * @brief getLastModifiedDtStr Get the last date at which the model was modified and persisted in the database
  202. * @return QString: Last modified and persisted date as a string
  203. */
  204. inline QString getLastModifiedDtStr() const { return lastModifiedDateTime; }
  205. /**
  206. * @brief getTableName The name of database table corresponding to the model
  207. * @return QString: Name of database table and of the model
  208. */
  209. inline QString getTableName() const { return name; }
  210. /**
  211. * @brief findProperty Find a property with its name
  212. * @param propertyName The name of the property
  213. * @return QMetaProperty: The property object
  214. */
  215. QMetaProperty findProperty(const QString &propertyName);
  216. /**
  217. * @brief propertyType Find the type of a property value from the property name
  218. * @param propertyName The name of the property
  219. * @return QVariant::Type: Type of the property
  220. */
  221. inline QVariant::Type propertyType(const QString &propertyName)
  222. {
  223. return findProperty(propertyName).type();
  224. }
  225. /**
  226. * @brief computePropsMap Iterate on all the model properties to insert them in a map
  227. * @param m The model that should be used (it often is "*this")
  228. * @return QMap<QString, QVariant>: A map of all the model properties
  229. */
  230. QMap<QString, QVariant> computePropsMap(Model &model);
  231. /**
  232. * @brief toJson Convert the model data (its property name and value pairs) in JSON format
  233. * @return QJsonObject: A JSON version of the model
  234. */
  235. inline QJsonObject toJson() { return QJsonObject::fromVariantMap(computePropsMap(*this)); }
  236. protected:
  237. /**
  238. * @brief preSaveCheck Perform some checks before persisting (saving) the model instance.
  239. * The persisting is done only if the checks where successful.
  240. * @return Bool: Was the check successful ?
  241. */
  242. virtual bool preSaveCheck() const { return true; }
  243. /**
  244. * @brief customizeField Allow to give special instructions when a field is created in the database.
  245. */
  246. virtual void customizeField(const QString &fieldName,
  247. const QVariant::Type &type,
  248. const QString &tableName) const;
  249. signals:
  250. void idChanged();
  251. void createdDateTimeChanged();
  252. void lastModifiedDateTimeChanged();
  253. };
  254. CWF_END_NAMESPACE
  255. #endif // MODEL_HH