| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #ifndef MODEL_HH
- #define MODEL_HH
- #include "metaclassparser.h"
- #include "modelbasicoperation.h"
- #include "sqlquery.h"
- #include <QDateTime>
- #include <QDebug>
- #include <QMetaObject>
- #include <QMetaProperty>
- #include <QObject>
- #include <memory>
- CWF_BEGIN_NAMESPACE
- /**
- * @brief The Model class implements basic ORM features and should be used as base class for every model (or entity).
- *
- * The class allows any derived model to be saved, retrieved or deleted from the database in very direct fashion
- * (see the example below). By default, the class contains three properties that should not be overriden:
- * - 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.
- * - createdDateTime : The date at which the model was first created.
- * - lastModifiedDateTime : The latest date at which the model was modified.
- * These properties will be added to every model.
- *
- * Each model is represented by a table in the database which is identical to the name of the model.
- *
- * A typical model is defined as:
- *
- * ```cpp
- * class UserModel : public Model
- * {
- * Q_OBJECT
- *
- * Q_PROPERTY(QString email MEMBER email NOTIFY emailChanged)
- *
- * public:
- * UserModel() : Model("user") // Name of the model and database table
- * {
- * }
- * ~UserModel() override;
- *
- * signals:
- * void emailChanged();
- *
- * private:
- * QString email;
- * }
- * ```
- *
- * And can be used in a controller with:
- * ```cpp
- * // Create an empty instance of your model
- * MyModel myModel;
- *
- * // Set some values
- * myModel.setEmail(myEmail);
- *
- * // Save it in the database
- * myModel.save();
- *
- * // Get the database id of the model just persisted.
- * int myModelId = myModel.getId();
- *
- * // Create another instance
- * MyModel myModel2;
- *
- * // Load the first instance data from the database
- * myModel2.build(myModelId); // We use the id of the first instance
- *
- * // Check the object was loaded
- * if(!myModel2.getWasBuild() )
- * {
- * // Error: it was not loaded for some reason...
- * }
- *
- * // Delete the object from the database
- * myModel2.remove();
- * ```
- */
- class CPPWEBFRAMEWORKSHARED_EXPORT Model : public QObject
- {
- Q_OBJECT
- protected:
- ModelBasicOperation basicOperation;
- private:
- Q_PROPERTY(qint64 id MEMBER id NOTIFY idChanged)
- Q_PROPERTY(QString createdDateTime MEMBER createdDateTime NOTIFY createdDateTimeChanged)
- Q_PROPERTY(
- QString lastModifiedDateTime MEMBER lastModifiedDateTime NOTIFY lastModifiedDateTimeChanged)
- /**
- * @brief id The database id of the model
- * 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
- * of the entity stored in the database) or if a user manually set the variable before.
- */
- QString name; ///< @brief name The name of the model
- QString dtFormat = "dd/MM/yyyy hh:mm:ss.zzz"; ///< @brief Format of the date used in this class
- QString createdDateTime; ///< @brief First save in the database date
- QString lastModifiedDateTime; ///< @brief Last modified and persisted date
- qint64 id = -1;
- qint64 version; ///< @brief The version of the table (database side)
- bool built = false; ///< @brief Was the model instance populated with data ?
- private:
- void verifyDbTableExist(); ///< @brief Check the database contains table corresponding to this model. Also create or update the table if needed.
- void verifyDbFields(); ///< @brief Check the database table contains all required fields (columns). If not, create them.
- public:
- /**
- * @brief Constructor
- */
- explicit Model(SqlDatabaseStorage &connection, const QString &name)
- : basicOperation(connection)
- , name(name)
- {}
- /**
- * @brief Destructor
- */
- virtual ~Model() = default;
- /**
- * @brief updateDB Will create or update the database schema to match the model class.
- * This allows to create a working table from scratch or to update one. Note that a table update can add new
- * fields (Qt properties in the model code) but cannot remove any. Therefore, a developer should only add new
- * properties to a model and never remove one.
- */
- void updateDB();
- /**
- * @brief build Populate the model with data from the database.
- * @param id The id of the data to be used to populate the model. id = -1 indicates an insertion. id != -1 indicates an update.
- */
- inline void build(const qint64 &id = -1)
- {
- build({{"id", QVariant::fromValue(this->id = id)}});
- }
- /**
- * @brief build Populate the model with data from the database.
- * @param selectCondition A map ([propertyName] = propertyValue) of property values
- * used to choose which data to insert in the model.
- *
- * The first entry of database table that matchs all the property values will be used to populate the model.
- */
- void build(const QMap<QString, QVariant> &selectCondition);
- /**
- * @brief buildFromJson Populate a model from json data
- * @param json The data used to populate the model instance
- * @param withTableNamePrefix Are the date properties prefixed with the name of this model db table ? This is false by default.
- */
- void buildFromJson(const QJsonObject &json, bool withTableNamePrefix = false);
- /**
- * @brief save Persist the model in the database
- * @return Bool: Was the model correctly persisted ?
- */
- bool save();
- /**
- * @brief remove Delete the model from the database
- * @return Bool: Was the data removed without error ?
- */
- inline bool remove() { return basicOperation.remove(getTableName(), id); }
- /**
- * @brief setCreatedDt Manually set the creation date
- * @param dt Date of the model first save into the database.
- */
- void setCreatedDt(const QDateTime &dt);
- /**
- * @brief setLastModifiedDt Set the last date at which the model was persisted in the database.
- * @param dt The date to be used.
- */
- void setLastModifiedDt(const QDateTime &dt);
- /**
- * @brief setWasBuild Set the "was build" flag that indicate if a model instance was correctly populated (build) by data.
- * @param b The flag.
- */
- inline void setWasBuild(bool b) { built = b; }
- /**
- * @brief getWasBuild Get the value of the "was build" flag.
- * @return Bool: Was the model instance populated by data from the database ?
- */
- inline bool getWasBuild() const { return built; }
- /**
- * @brief getId Get the id of the model
- * @return qint64: The id of the model
- */
- inline qint64 getId() const { return id; }
- /**
- * @brief getCreatedDt Get the creation date of the model
- * @return QDateTime: Creation date
- */
- inline QDateTime getCreatedDt() const
- {
- return QDateTime::fromString(createdDateTime, dtFormat);
- }
- /**
- * @brief getCreatedDtStr Get the creation date as a string
- * @return QString: Creation date as a string
- */
- inline QString getCreatedDtStr() const { return createdDateTime; }
- /**
- * @brief getLastModifiedDt Get the last date at which the model was modified and persisted in the database
- * @return QDateTime: Last modified and persisted date
- */
- inline QDateTime getLastModifiedDt() const
- {
- return QDateTime::fromString(lastModifiedDateTime, dtFormat);
- }
- /**
- * @brief getLastModifiedDtStr Get the last date at which the model was modified and persisted in the database
- * @return QString: Last modified and persisted date as a string
- */
- inline QString getLastModifiedDtStr() const { return lastModifiedDateTime; }
- /**
- * @brief getTableName The name of database table corresponding to the model
- * @return QString: Name of database table and of the model
- */
- inline QString getTableName() const { return name; }
- /**
- * @brief findProperty Find a property with its name
- * @param propertyName The name of the property
- * @return QMetaProperty: The property object
- */
- QMetaProperty findProperty(const QString &propertyName);
- /**
- * @brief propertyType Find the type of a property value from the property name
- * @param propertyName The name of the property
- * @return QVariant::Type: Type of the property
- */
- inline QVariant::Type propertyType(const QString &propertyName)
- {
- return findProperty(propertyName).type();
- }
- /**
- * @brief computePropsMap Iterate on all the model properties to insert them in a map
- * @param m The model that should be used (it often is "*this")
- * @return QMap<QString, QVariant>: A map of all the model properties
- */
- QMap<QString, QVariant> computePropsMap(Model &model);
- /**
- * @brief toJson Convert the model data (its property name and value pairs) in JSON format
- * @return QJsonObject: A JSON version of the model
- */
- inline QJsonObject toJson() { return QJsonObject::fromVariantMap(computePropsMap(*this)); }
- protected:
- /**
- * @brief preSaveCheck Perform some checks before persisting (saving) the model instance.
- * The persisting is done only if the checks where successful.
- * @return Bool: Was the check successful ?
- */
- virtual bool preSaveCheck() const { return true; }
- /**
- * @brief customizeField Allow to give special instructions when a field is created in the database.
- */
- virtual void customizeField(const QString &fieldName,
- const QVariant::Type &type,
- const QString &tableName) const;
- signals:
- void idChanged();
- void createdDateTimeChanged();
- void lastModifiedDateTimeChanged();
- };
- CWF_END_NAMESPACE
- #endif // MODEL_HH
|