Skip to content

Commit

Permalink
Generates list from sqlite db
Browse files Browse the repository at this point in the history
  • Loading branch information
shangar21 committed Sep 1, 2024
1 parent deda0c3 commit b0439d7
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/mainwindow
${CMAKE_SOURCE_DIR}/src/viewrecipewindow
${CMAKE_SOURCE_DIR}/src/database
# ${CMAKE_SOURCE_DIR}/src/database/modelStructs
)

add_executable(recipe_cli
Expand All @@ -31,6 +30,8 @@ add_executable(recipe_cli
src/addrecipewindow/addrecipewindow.h
src/viewrecipewindow/viewrecipewindow.cpp
src/viewrecipewindow/viewrecipewindow.h
src/generatelistwindow/generatelistwindow.cpp
src/generatelistwindow/generatelistwindow.h
src/database/SQLiteHelper.cpp
src/database/SQLiteHelper.h
)
Expand Down
88 changes: 88 additions & 0 deletions src/database/SQLiteHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,91 @@ bool SQLiteHelper::insertRecipeIngredientMap(int recipeId,
sqlite3_finalize(stmt);
return success;
}

std::vector<std::tuple<Ingredient, float, Unit>> SQLiteHelper::fetchRecipeIngredients(int recipeId) {
std::vector<std::tuple<Ingredient, float, Unit>> ingredientList;

std::string query = R"(
WITH IngredientData AS (
SELECT
ri.ingredient_id,
i.name AS ingredient_name,
ri.quantity,
ri.unit_id,
u.name AS unit_name
FROM
recipe_ingredients ri
JOIN
ingredients i ON ri.ingredient_id = i.id
JOIN
units u ON ri.unit_id = u.id
WHERE
ri.recipe_id = ?
),
AggregatedData AS (
SELECT
id.ingredient_id,
id.ingredient_name,
SUM(CASE
WHEN uc.from_unit_id = id.unit_id THEN id.quantity * uc.factor
WHEN uc.to_unit_id = id.unit_id THEN id.quantity / uc.factor
ELSE id.quantity
END) AS aggregated_quantity,
CASE
WHEN uc.from_unit_id = id.unit_id THEN uc.to_unit_id
WHEN uc.to_unit_id = id.unit_id THEN uc.from_unit_id
ELSE id.unit_id
END AS resulting_unit_id,
COALESCE(
(SELECT u2.name FROM units u2 WHERE u2.id =
CASE
WHEN uc.from_unit_id = id.unit_id THEN uc.to_unit_id
WHEN uc.to_unit_id = id.unit_id THEN uc.from_unit_id
ELSE id.unit_id
END),
id.unit_name
) AS resulting_unit_name
FROM
IngredientData id
LEFT JOIN
unit_conversions uc ON (id.unit_id = uc.from_unit_id OR id.unit_id = uc.to_unit_id)
GROUP BY
id.ingredient_id, id.ingredient_name, resulting_unit_id, resulting_unit_name
)
SELECT
ingredient_id,
ingredient_name,
aggregated_quantity,
resulting_unit_id,
resulting_unit_name
FROM
AggregatedData;
)";

sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db_, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
qDebug() << "Failed to prepare statement:" << sqlite3_errmsg(db_);
return ingredientList;
}

sqlite3_bind_int(stmt, 1, recipeId);

while (sqlite3_step(stmt) == SQLITE_ROW) {
Ingredient ingredient;
ingredient.id = sqlite3_column_int(stmt, 0);
ingredient.name = QString::fromUtf8(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)));

float quantity = static_cast<float>(sqlite3_column_double(stmt, 2));

Unit unit;
unit.id = sqlite3_column_int(stmt, 3);
unit.name = QString::fromUtf8(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 4)));

ingredientList.emplace_back(ingredient, quantity, unit);
}

sqlite3_finalize(stmt);

return ingredientList;
}
4 changes: 4 additions & 0 deletions src/database/SQLiteHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <sqlite3.h>
#include <string>
#include <vector>
#include <QDebug>

class SQLiteHelper {
public:
Expand All @@ -22,6 +23,9 @@ class SQLiteHelper {
int insertRecipe(Recipe &recipe);
bool insertRecipeIngredientMap(int recipeId, Ingredient &ingredient,
float quantity, Unit &unit);
std::vector<std::tuple<Ingredient, float, Unit>>
fetchRecipeIngredients(int recipeId);


private:
sqlite3 *db_;
Expand Down
Binary file modified src/database/db.sqlite3
Binary file not shown.
76 changes: 76 additions & 0 deletions src/generatelistwindow/generatelistwindow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "generatelistwindow.h"
#include <QMessageBox>

GenerateGroceryListWindow::GenerateGroceryListWindow(QWidget *parent)
: QDialog(parent) {
setupUI();
}

GenerateGroceryListWindow::~GenerateGroceryListWindow() {}

void GenerateGroceryListWindow::setupUI() {
setWindowTitle("Generate Grocery List");
resize(500, 400);

QVBoxLayout *mainLayout = new QVBoxLayout(this);

recipeScrollArea = new QScrollArea(this);
QWidget *scrollAreaWidget = new QWidget(recipeScrollArea);
scrollAreaLayout = new QVBoxLayout(scrollAreaWidget);
recipeScrollArea->setWidget(scrollAreaWidget);
recipeScrollArea->setWidgetResizable(true);

generateListButton = new QPushButton("Generate List", this);
connect(generateListButton, &QPushButton::clicked, this, &GenerateGroceryListWindow::generateGroceryList);

mainLayout->addWidget(recipeScrollArea);
mainLayout->addWidget(generateListButton);

loadRecipes();
}

void GenerateGroceryListWindow::loadRecipes() {
std::vector<Recipe> recipes = SQLiteHelper().fetchRecipes();

for (Recipe recipe : recipes) {
QWidget *recipeWidget = new QWidget(this);
QHBoxLayout *recipeLayout = new QHBoxLayout(recipeWidget);

QLabel *recipeLabel = new QLabel(recipe.title, recipeWidget);
QSpinBox *quantitySpinBox = new QSpinBox(recipeWidget);
quantitySpinBox->setRange(0, 100);

recipeLayout->addWidget(recipeLabel);
recipeLayout->addWidget(quantitySpinBox);

scrollAreaLayout->addWidget(recipeWidget);

recipeSpinBoxes[recipe.id] = quantitySpinBox;
}
}

void GenerateGroceryListWindow::generateGroceryList() {
QMap<QString, float> aggregatedIngredients;

for (auto it = recipeSpinBoxes.begin(); it != recipeSpinBoxes.end(); it++) {
int recipeId = it.key();
int quantity = it.value()->value();

if (quantity > 0) {
std::vector<std::tuple<Ingredient, float, Unit>> recipeIngredients =
SQLiteHelper().fetchRecipeIngredients(recipeId);

for (auto &[ingredient, measure, unit] : recipeIngredients){
QString key = QString("%1 (%2)").arg(ingredient.name).arg(unit.name);
aggregatedIngredients[key] += measure * quantity;
}
}
}

QStringList output;
for (auto it = aggregatedIngredients.begin(); it != aggregatedIngredients.end(); it++){
output.append(QString("%1: %2").arg(it.key()).arg(it.value()));
}

QMessageBox::information(this, "Grocery List", output.join("\n"));
}
34 changes: 34 additions & 0 deletions src/generatelistwindow/generatelistwindow.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include "SQLiteHelper.h"
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QMainWindow>
#include <QMap>
#include <QPushButton>
#include <QScrollArea>
#include <QSpinBox>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QWidget>
#include <vector>

class GenerateGroceryListWindow : public QDialog {
Q_OBJECT

public:
GenerateGroceryListWindow(QWidget *parent = nullptr);
~GenerateGroceryListWindow();

private:
QScrollArea *recipeScrollArea;
QVBoxLayout *scrollAreaLayout;
QPushButton *generateListButton;
QMap<int, QSpinBox *> recipeSpinBoxes;

void loadRecipes();
void generateGroceryList();
void setupUI();
};
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ int main(int argc, char *argv[]) {
qRegisterMetaType<Recipe>("Recipe");

MainWindow window;
window.setWindowTitle("Recipe CLI - Main Window");
window.setWindowTitle("Recipe GUI - Main Window");
window.resize(300, 200);
window.show();

Expand Down
15 changes: 15 additions & 0 deletions src/mainwindow/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ void MainWindow::setupUI() {

connect(viewRecipeButton, &QPushButton::clicked, this,
&MainWindow::openViewRecipeWindow);

connect(generateGroceryListButton, &QPushButton::clicked, this,
&MainWindow::openGenerateGroceryListWindow);
}

void MainWindow::openAddRecipeWindow() {
Expand All @@ -53,3 +56,15 @@ void MainWindow::openViewRecipeWindow() {
viewRecipeWindow->raise();
viewRecipeWindow->activateWindow();
}

void MainWindow::openGenerateGroceryListWindow() {
if (!generateGroceryListWindow) {
generateGroceryListWindow = new GenerateGroceryListWindow(this);
generateGroceryListWindow->setAttribute(Qt::WA_DeleteOnClose);
connect(generateGroceryListWindow, &QWidget::destroyed, this,
[this]() { generateGroceryListWindow = nullptr; });
}
generateGroceryListWindow->show();
generateGroceryListWindow->raise();
generateGroceryListWindow->activateWindow();
}
3 changes: 3 additions & 0 deletions src/mainwindow/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define MAINWINDOW_H

#include "addrecipewindow.h"
#include "generatelistwindow.h"
#include "viewrecipewindow.h"
#include <QMainWindow>

Expand All @@ -15,9 +16,11 @@ class MainWindow : public QMainWindow {
private:
AddRecipeWindow *addRecipeWindow = nullptr;
ViewRecipeWindow *viewRecipeWindow = nullptr;
GenerateGroceryListWindow *generateGroceryListWindow = nullptr;
void setupUI(); // Function to set up the UI elements
void openAddRecipeWindow();
void openViewRecipeWindow();
void openGenerateGroceryListWindow();
};

#endif // MAINWINDOW_H

0 comments on commit b0439d7

Please sign in to comment.