File indexing completed on 2024-05-12 17:24:09

0001 #include "database.h"
0002 
0003 #include <QStandardPaths>
0004 #include <ThreadedDatabase>
0005 #include <QDir>
0006 #include <QStringBuilder>
0007 #include <QDateTime>
0008 #include <QCoroTask>
0009 #include <QCoroFuture>
0010 
0011 using namespace DB;
0012 
0013 HealthEvent::HealthEvent(int _health_date, int _health)
0014     : health_date(_health_date)
0015     , health(_health)
0016 {}
0017 
0018 Database::Database()
0019 {
0020     const auto databaseDirectory = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
0021 
0022     // Make sure the database directory exists
0023     QDir(databaseDirectory).mkpath(QStringLiteral("."));
0024 
0025     DatabaseConfiguration config;
0026     config.setDatabaseName(databaseDirectory % QDir::separator() % "plants.sqlite");
0027     config.setType(DatabaseType::SQLite);
0028 
0029     m_database = ThreadedDatabase::establishConnection(config);
0030     m_database->runMigrations(":/contents/migrations/");
0031 }
0032 
0033 QCoro::Task<DB::Plant::Id> Database::addPlant(const QString &name, const QString &species, const QString &imgUrl, const int waterInterval, const QString location, const int dateOfBirth, const int lastWatered, const int healthDate, const int health)
0034 {
0035     auto id = co_await m_database->getResult<SingleValue<int>>("insert into plants (name, species, img_url, water_intervall, location, date_of_birth) values (?, ?, ?, ?, ?, ?) returning plant_id", name, species, imgUrl, waterInterval, location, dateOfBirth);
0036 
0037     m_database->execute("insert into water_history (plant_id, water_date) values (?, ?)", id.value().value, lastWatered);
0038     m_database->execute("insert into health_history (plant_id, health_date, health) values (?, ?, ?)", id.value().value, healthDate, health);
0039 
0040     co_return id.value().value;
0041 }
0042 
0043 void Database::editPlant(const DB::Plant::Id plantId, const QString &name, const QString &species, const QString &imgUrl, const int waterIntervall, const QString location, const int dateOfBirth)
0044 {
0045 
0046     auto future = m_database->getResult<SingleValue<int>>("update plants SET name = ?, species = ?, img_url = ?, water_intervall = ?, location = ?, date_of_birth = ? where plant_id = ?", name, species, imgUrl, waterIntervall, location, dateOfBirth, plantId);
0047     QCoro::connect(std::move(future), this, [=, this](auto) {
0048         Q_EMIT plantChanged(plantId);
0049     });
0050 }
0051 
0052 void Database::deletePlant(const DB::Plant::Id plantId)
0053 {
0054     auto future = m_database->execute("delete from plants where plant_id = ?", plantId);
0055     QCoro::connect(std::move(future), this, [=, this]() {
0056         m_database->execute("delete from water_history where plant_id = ?", plantId);
0057         m_database->execute("delete from health_history where plant_id = ?", plantId);
0058         Q_EMIT plantChanged(plantId);
0059     });
0060 }
0061 QFuture<std::vector<Plant>> Database::plants()
0062 {
0063     return m_database->getResults<Plant>(R"(
0064     select
0065         plants.plant_id, name, species, img_url, water_intervall, location, date_of_birth, parent, max(water_date), max(health_date) as latest_health_date, health
0066     from
0067         plants
0068     left join
0069         water_history
0070     on
0071         plants.plant_id = water_history.plant_id
0072     left join
0073         health_history
0074     on
0075         plants.plant_id = health_history.plant_id
0076     group by
0077         plants.plant_id
0078     )" );
0079 }
0080 
0081 QFuture<std::optional<Plant>> Database::plant(int plant_id)
0082 {
0083     return m_database->getResult<Plant>(R"(
0084     select
0085         plants.plant_id, name, species, img_url, water_intervall, location, date_of_birth, parent, max(water_date), max(health_date) as latest_health_date, health
0086     from
0087         plants
0088     left join
0089         water_history
0090     on
0091         plants.plant_id = water_history.plant_id
0092     left join
0093         health_history
0094     on
0095         plants.plant_id = health_history.plant_id
0096     where plants.plant_id = ?
0097     group by
0098         plants.plant_id
0099     )", plant_id);
0100 }
0101 
0102 QFuture<std::vector<SingleValue<int>>> Database::waterEvents(int plantId)
0103 {
0104     return m_database->getResults<SingleValue<int>>("select water_date from water_history where plant_id = ?", plantId);
0105 }
0106 
0107 QFuture<std::vector<HealthEvent>> Database::healthEvents(int plantId)
0108 {
0109     return m_database->getResults<HealthEvent>("select health_date, health from health_history where plant_id = ?", plantId);
0110 }
0111 
0112 void Database::waterPlant(const int plantId, const int waterDate)
0113 {
0114     m_database->execute("insert into water_history (plant_id, water_date) values (?, ?)", plantId, waterDate);
0115     Q_EMIT plantChanged(plantId);
0116 }
0117 
0118 void Database::addHealthEvent(const int plantId, const int waterDate, const int health)
0119 {
0120     m_database->execute("insert into health_history (plant_id, health_date, health) values (?, ?, ?)", plantId, waterDate, health);
0121     Q_EMIT plantChanged(plantId);
0122 }
0123 
0124 QFuture<std::optional<SingleValue<int>>> Database::getLastHealthDate(const int plantId)
0125 {
0126     return m_database->getResult<SingleValue<int>>("select health_date from health_history where plant_id = ? order by desc limit 1", plantId);
0127 
0128 }
0129 
0130 //void Database::replaceLastHealthEvent(const int plantId, const int waterDate, const int health)
0131 //{
0132 //    m_database->execute("insert into health_history (plant_id, health_date, health) values (?, ?, ?)", plantId, waterDate, health);
0133 //}
0134 
0135 Database &Database::instance()
0136 {
0137     static Database inst;
0138     return inst;
0139 }