summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-04-01 22:18:46 -0700
committerrtk0c <[email protected]>2021-04-01 22:18:46 -0700
commit2f4b9db39239ed5150094a81743beea42a3eedc2 (patch)
tree7d5795f7c23eb4f92ccffe2476da019db9977f2b
parent44f5fa5c8f258e8fc1f7d7e2e45e0485bd6cc490 (diff)
Initial work on SQLite database
-rw-r--r--core/CMakeLists.txt2
-rw-r--r--core/src/Entrypoint/main.cpp2
-rw-r--r--core/src/Model/Items.cpp10
-rw-r--r--core/src/Model/Items.hpp3
-rw-r--r--core/src/Model/Project.cpp40
-rw-r--r--core/src/Model/Project.hpp21
-rw-r--r--core/src/Model/Stock.cpp1
-rw-r--r--core/src/Model/Stock.hpp1
-rw-r--r--core/src/Model/TransactionDatabase.cpp41
-rw-r--r--core/src/Model/TransactionDatabase.hpp34
-rw-r--r--core/src/Model/fwd.hpp3
-rw-r--r--core/src/UI/UI_MainWindow.cpp31
12 files changed, 135 insertions, 54 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 53dd498..0432ed1 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -37,7 +37,7 @@ add_source_group(MODEL_MODULE_SOURCES
src/Model/GlobalStates.cpp
src/Model/Items.cpp
src/Model/Project.cpp
- src/Model/Stock.cpp
+ src/Model/TransactionDatabase.cpp
)
add_source_group(UI_MODULE_SOURCES
diff --git a/core/src/Entrypoint/main.cpp b/core/src/Entrypoint/main.cpp
index 357c333..4f5dc4b 100644
--- a/core/src/Entrypoint/main.cpp
+++ b/core/src/Entrypoint/main.cpp
@@ -12,8 +12,6 @@
#include "Utils/I18n.hpp"
#include "Utils/Sigslot.hpp"
-#include <glad/glad.h>
-#include <GLFW/glfw3.h>
#include <IconsFontAwesome.h>
#include <imgui.h>
#include <argparse/argparse.hpp>
diff --git a/core/src/Model/Items.cpp b/core/src/Model/Items.cpp
index 7679eb9..2951666 100644
--- a/core/src/Model/Items.cpp
+++ b/core/src/Model/Items.cpp
@@ -8,14 +8,24 @@ void ProductItem::SetDescription(std::string description) {
mDescription = std::move(description);
}
+int ProductItem::GetStock() const {
+ return mStock;
+}
+
+void ProductItem::SetStock(int stock) {
+ mStock = stock;
+}
+
Json::Value ProductItem::Serialize() const {
Json::Value elm;
elm["Description"] = mDescription;
+ elm["Stock"] = mStock;
return elm;
}
void ProductItem::Deserialize(const Json::Value& elm) {
mDescription = elm["Description"].asString();
+ mStock = elm["Stock"].asInt();
}
const std::string& FactoryItem::GetDescription() const {
diff --git a/core/src/Model/Items.hpp b/core/src/Model/Items.hpp
index e20a290..14b62f3 100644
--- a/core/src/Model/Items.hpp
+++ b/core/src/Model/Items.hpp
@@ -175,12 +175,15 @@ public:
class ProductItem : public ItemBase<ProductItem> {
private:
std::string mDescription;
+ int mStock = 0;
public:
using ItemBase::ItemBase;
const std::string& GetDescription() const;
void SetDescription(std::string description);
+ int GetStock() const;
+ void SetStock(int stock);
Json::Value Serialize() const;
void Deserialize(const Json::Value& elm);
diff --git a/core/src/Model/Project.cpp b/core/src/Model/Project.cpp
index cdb88c6..c20e0c8 100644
--- a/core/src/Model/Project.cpp
+++ b/core/src/Model/Project.cpp
@@ -21,23 +21,22 @@ void ReadItemList(ItemList<T>& list, const fs::path& filePath) {
}
}
-Project Project::Load(const fs::path& projectFilePath) {
+Project::Project(const fs::path& rootPath)
+ : mRootPath{ rootPath }
+ , mRootPathString{ mRootPath.string() }
+ , mDb(*this) {
// TODO better diagnostic
const char* kInvalidFormatErr = "Failed to load project: invalid format.";
- std::ifstream ifs(projectFilePath);
+ std::ifstream ifs(rootPath / "cplt_project.json");
if (!ifs) {
std::string message;
message += "Failed to load project file at '";
- message += projectFilePath.string();
+ message += rootPath.string();
message += "'.";
throw std::runtime_error(message);
}
- Project proj;
- proj.mRootPath = projectFilePath.parent_path();
- proj.mRootPathString = proj.mRootPath.string();
-
{
Json::Value root;
ifs >> root;
@@ -48,30 +47,23 @@ Project Project::Load(const fs::path& projectFilePath) {
}
if (auto& name = croot["Name"]; name.isString()) {
- proj.mName = name.asString();
+ mName = name.asString();
} else {
throw std::runtime_error(kInvalidFormatErr);
}
}
- auto itemsDir = proj.mRootPath / "items";
- ReadItemList(proj.Products, itemsDir / "products.json");
- ReadItemList(proj.Factories, itemsDir / "factories.json");
- ReadItemList(proj.Customers, itemsDir / "customers.json");
-
- return proj;
-}
-
-Project Project::LoadDir(const std::filesystem::path& projectPath) {
- return Load(projectPath / "cplt_project.json");
+ auto itemsDir = mRootPath / "items";
+ ReadItemList(Products, itemsDir / "products.json");
+ ReadItemList(Factories, itemsDir / "factories.json");
+ ReadItemList(Customers, itemsDir / "customers.json");
}
-Project Project::Create(std::string name, const fs::path& path) {
- Project proj;
- proj.mRootPath = path;
- proj.mRootPathString = path.string();
- proj.mName = std::move(name);
- return proj;
+Project::Project(std::filesystem::path rootPath, std::string name)
+ : mRootPath{ std::move(rootPath) }
+ , mRootPathString{ mRootPath.string() }
+ , mName{ std::move(name) }
+ , mDb(*this) {
}
const fs::path& Project::GetPath() const {
diff --git a/core/src/Model/Project.hpp b/core/src/Model/Project.hpp
index 280eaf3..8d437ea 100644
--- a/core/src/Model/Project.hpp
+++ b/core/src/Model/Project.hpp
@@ -1,10 +1,11 @@
#pragma once
#include "Model/Items.hpp"
+#include "Model/TransactionDatabase.hpp"
+#include <json/forwards.h>
#include <filesystem>
#include <string>
-#include <json/forwards.h>
class Project {
public:
@@ -16,15 +17,20 @@ private:
std::filesystem::path mRootPath;
std::string mRootPathString;
std::string mName;
+ TransactionDatabase mDb;
public:
- /// Load the project from a cplt_project.json file.
- static Project Load(const std::filesystem::path& projectFilePath);
- /// Load the project from the directory containing the cplt_project.json file.
- static Project LoadDir(const std::filesystem::path& projectPath);
+ /// Load the project from a directory containing the cplt_project.json file.
+ Project(const std::filesystem::path& rootPath);
+
/// Create a project with the given name in the given path. Note that the path should be a directory that will contain the project files once created.
/// This function assumes the given directory will exist and is empty.
- static Project Create(std::string name, const std::filesystem::path& path);
+ Project(std::filesystem::path rootPath, std::string name);
+
+ Project(const Project&) = delete;
+ Project& operator=(const Project&) = delete;
+ Project(Project&&) = default;
+ Project& operator=(Project&&) = default;
/// Path to a *directory* that contains the project file.
const std::filesystem::path& GetPath() const;
@@ -35,7 +41,4 @@ public:
Json::Value Serialize();
void WriteToDisk();
-
-private:
- Project() = default;
};
diff --git a/core/src/Model/Stock.cpp b/core/src/Model/Stock.cpp
deleted file mode 100644
index a56de03..0000000
--- a/core/src/Model/Stock.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include "Stock.hpp"
diff --git a/core/src/Model/Stock.hpp b/core/src/Model/Stock.hpp
deleted file mode 100644
index 6f70f09..0000000
--- a/core/src/Model/Stock.hpp
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/core/src/Model/TransactionDatabase.cpp b/core/src/Model/TransactionDatabase.cpp
new file mode 100644
index 0000000..c28db0d
--- /dev/null
+++ b/core/src/Model/TransactionDatabase.cpp
@@ -0,0 +1,41 @@
+#include "TransactionDatabase.hpp"
+
+#include "Model/Project.hpp"
+
+#include <filesystem>
+#include <stdexcept>
+#include <string>
+
+namespace fs = std::filesystem;
+
+static bool TableExists(sqlite3* db, const char* table, const char* column = nullptr) {
+ return sqlite3_table_column_metadata(db, nullptr, table, column, nullptr, nullptr, nullptr, nullptr, nullptr) == SQLITE_OK;
+}
+
+TransactionDatabase::TransactionDatabase(Project& project)
+ : mProject{ &project }
+ , mDatabase{ nullptr } {
+
+ fs::path dbDir = project.GetPath() / "databases";
+ fs::create_directories(dbDir);
+
+ fs::path dbPath = dbDir / "transactions.sqlite3";
+#if PLATFORM_WIN32
+ if (int rc = sqlite3_open16(dbPath.c_str(), &mDatabase); rc) {
+#else
+ if (int rc = sqlite3_open(transactionDbPath.c_str(), &mDatabase); rc) {
+#endif
+ sqlite3_close(mDatabase);
+
+ std::string message;
+ message += "Failed to open SQLite database for transactions. Error code: ";
+ message += rc;
+ message += ".";
+ throw std::runtime_error(message);
+ }
+}
+
+TransactionDatabase::~TransactionDatabase() {
+ sqlite3_close(mDatabase);
+ mDatabase = nullptr;
+}
diff --git a/core/src/Model/TransactionDatabase.hpp b/core/src/Model/TransactionDatabase.hpp
new file mode 100644
index 0000000..191a8b8
--- /dev/null
+++ b/core/src/Model/TransactionDatabase.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "cplt_fwd.hpp"
+
+#include <sqlite3.h>
+#include <cstdint>
+
+struct DeliveryId {
+ int64_t id;
+};
+
+class DeliveryTable {
+};
+
+class OrdersTable {
+};
+
+class PurchasesTable {
+};
+
+class TransactionDatabase {
+private:
+ Project* mProject;
+ sqlite3* mDatabase;
+
+public:
+ TransactionDatabase(Project& project);
+ ~TransactionDatabase();
+
+ TransactionDatabase(const TransactionDatabase&) = delete;
+ TransactionDatabase& operator=(const TransactionDatabase&) = delete;
+ TransactionDatabase(TransactionDatabase&&) = default;
+ TransactionDatabase& operator=(TransactionDatabase&&) = default;
+};
diff --git a/core/src/Model/fwd.hpp b/core/src/Model/fwd.hpp
index 146f74a..2d8d2ec 100644
--- a/core/src/Model/fwd.hpp
+++ b/core/src/Model/fwd.hpp
@@ -14,3 +14,6 @@ class CustomerItem;
// Project.hpp
class Project;
+
+// TransactionDatabase.hpp
+class TransactionDatabase;
diff --git a/core/src/UI/UI_MainWindow.cpp b/core/src/UI/UI_MainWindow.cpp
index 661c535..a47efab 100644
--- a/core/src/UI/UI_MainWindow.cpp
+++ b/core/src/UI/UI_MainWindow.cpp
@@ -15,18 +15,6 @@
namespace fs = std::filesystem;
namespace {
-bool LoadProjectAt(const std::filesystem::path& path) {
- auto& uis = UIState::GetInstance();
- try {
- auto project = Project::Load(path);
- uis.SetCurrentProject(std::make_unique<Project>(std::move(project)));
-
- return true;
- } catch (const std::exception& e) {
- return false;
- }
-}
-
void ProjectTab_Normal() {
auto ls = LocaleStrings::Instance.get();
auto& gs = GlobalStates::GetInstance();
@@ -100,8 +88,7 @@ void ProjectTab_NoProject() {
if (ImGui::Button(ls->DialogConfirm.Get(), !dirNameIsValid || projectName.empty())) {
ImGui::CloseCurrentPopup();
- auto project = Project::Create(std::move(projectName), dirPath);
- uis.SetCurrentProject(std::make_unique<Project>(std::move(project)));
+ uis.SetCurrentProject(std::make_unique<Project>(std::move(dirPath), std::move(projectName)));
// Dialog just got closed, reset states
projectName = "";
@@ -123,7 +110,14 @@ void ProjectTab_NoProject() {
auto selection = pfd::open_file(ls->OpenProjectDialogTitle.Get()).result();
if (!selection.empty()) {
fs::path path(selection[0]);
- openErrorDialog = !LoadProjectAt(path);
+
+ try {
+ // Project's constructor wants a path to directory containing cplt_project.json
+ uis.SetCurrentProject(std::make_unique<Project>(path.parent_path()));
+ openErrorDialog = false;
+ } catch (const std::exception& e) {
+ openErrorDialog = true;
+ }
}
}
@@ -154,7 +148,12 @@ void ProjectTab_NoProject() {
ImGui::SameLine();
if (ImGui::Button(ICON_FA_FOLDER_OPEN)) {
- openErrorDialog = !LoadProjectAt(path / "cplt_project.json");
+ try {
+ uis.SetCurrentProject(std::make_unique<Project>(path));
+ openErrorDialog = false;
+ } catch (const std::exception& e) {
+ openErrorDialog = true;
+ }
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", ls->OpenRecentProjectTooltip.Get());