Shift to master. Not done but database abstraction is nearly done. #3
|
@ -24,7 +24,8 @@ SOURCES += model/recipe/instruction.cpp \
|
||||||
model/recipe/tags/recipetag.cpp \
|
model/recipe/tags/recipetag.cpp \
|
||||||
SQLite/sqlite3.c \
|
SQLite/sqlite3.c \
|
||||||
model/database/resulttable.cpp \
|
model/database/resulttable.cpp \
|
||||||
model/database/recipedatabase.cpp
|
model/database/recipedatabase.cpp \
|
||||||
|
utils/fileutils.cpp
|
||||||
|
|
||||||
HEADERS += model/recipe/instruction.h \
|
HEADERS += model/recipe/instruction.h \
|
||||||
model/recipe/recipe.h \
|
model/recipe/recipe.h \
|
||||||
|
@ -39,8 +40,7 @@ HEADERS += model/recipe/instruction.h \
|
||||||
SQLite/sqlite3ext.h \
|
SQLite/sqlite3ext.h \
|
||||||
model/database/resulttable.h \
|
model/database/resulttable.h \
|
||||||
model/database/recipedatabase.h \
|
model/database/recipedatabase.h \
|
||||||
utils/fileutils.h \
|
utils/fileutils.h
|
||||||
utils/stringutils.h
|
|
||||||
|
|
||||||
LIBS += -ldl \
|
LIBS += -ldl \
|
||||||
|
|
||||||
|
|
16
main.cpp
16
main.cpp
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include "model/database/database.h"
|
#include "model/database/database.h"
|
||||||
#include "model/database/recipedatabase.h"
|
#include "model/database/recipedatabase.h"
|
||||||
#include "utils/fileutils.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -14,12 +13,12 @@ int main(int argc, char *argv[])
|
||||||
//TESTING CODE
|
//TESTING CODE
|
||||||
|
|
||||||
RecipeDatabase recipeDB("recipes");
|
RecipeDatabase recipeDB("recipes");
|
||||||
recipeDB.storeIngredient(Ingredient("Apple", "Fruit"));
|
// recipeDB.storeIngredient(Ingredient("Apple", "Fruit"));
|
||||||
recipeDB.storeIngredient(Ingredient("Corn", "Vegetable"));
|
// recipeDB.storeIngredient(Ingredient("Corn", "Vegetable"));
|
||||||
recipeDB.storeIngredient(Ingredient("Lettuce", "Vegetable"));
|
// recipeDB.storeIngredient(Ingredient("Lettuce", "Vegetable"));
|
||||||
recipeDB.storeIngredient(Ingredient("Carrot", "Vegetable"));
|
// recipeDB.storeIngredient(Ingredient("Carrot", "Vegetable"));
|
||||||
|
|
||||||
recipeDB.executeSQL("SELECT * FROM ingredient;").printData();
|
// recipeDB.executeSQL("SELECT * FROM ingredient;").printData();
|
||||||
|
|
||||||
//TESTING CODE
|
//TESTING CODE
|
||||||
vector<RecipeIngredient> ri;
|
vector<RecipeIngredient> ri;
|
||||||
|
@ -28,6 +27,11 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
Recipe rec("Example", ri, Instruction("<b>BOLD</b><i>iTaLiCs</i>"), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f);
|
Recipe rec("Example", ri, Instruction("<b>BOLD</b><i>iTaLiCs</i>"), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f);
|
||||||
|
|
||||||
|
bool success = recipeDB.storeRecipe(rec);
|
||||||
|
printf("Storage successful: %d\n", success);
|
||||||
|
|
||||||
|
recipeDB.executeSQL("SELECT * FROM recipeIngredient;").printData();
|
||||||
|
|
||||||
w.loadFromRecipe(rec);
|
w.loadFromRecipe(rec);
|
||||||
|
|
||||||
return a.exec();
|
return a.exec();
|
||||||
|
|
|
@ -34,7 +34,6 @@ bool Database::insertInto(string tableName, vector<string> columnNames, vector<s
|
||||||
string cols = combineVector(columnNames, ", ");
|
string cols = combineVector(columnNames, ", ");
|
||||||
string vals = combineVector(values, ", ");
|
string vals = combineVector(values, ", ");
|
||||||
query += cols + ") VALUES (" + vals + ");";
|
query += cols + ") VALUES (" + vals + ");";
|
||||||
printf("Executing query: %s\n", query.c_str());
|
|
||||||
this->executeSQL(query);
|
this->executeSQL(query);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ RecipeDatabase::RecipeDatabase(string filename) : Database(filename){
|
||||||
this->ensureTablesExist();
|
this->ensureTablesExist();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecipeDatabase::storeRecipe(Recipe recipe){
|
bool RecipeDatabase::storeRecipe(Recipe recipe){
|
||||||
///TODO: Implement this in a smart way using transaction.
|
///TODO: Implement this in a smart way using transaction.
|
||||||
ResultTable t = this->executeSQL("SELECT * FROM recipe WHERE name='"+recipe.getName()+"';");
|
ResultTable t = this->executeSQL("SELECT * FROM recipe WHERE name='"+recipe.getName()+"';");
|
||||||
if (!t.isEmpty()){
|
if (!t.isEmpty()){
|
||||||
fprintf(stderr, "Error storing recipe: Recipe with name %s already exists.\n", recipe.getName().c_str());
|
fprintf(stderr, "Error storing recipe: Recipe with name %s already exists.\n", recipe.getName().c_str());
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
bool success = this->insertInto("recipe",
|
bool success = this->insertInto("recipe",
|
||||||
vector<string>({
|
vector<string>({
|
||||||
|
@ -27,24 +28,70 @@ void RecipeDatabase::storeRecipe(Recipe recipe){
|
||||||
}));
|
}));
|
||||||
if (success){
|
if (success){
|
||||||
//If successful, proceed to insert instructions, image, and ingredients.
|
//If successful, proceed to insert instructions, image, and ingredients.
|
||||||
|
int recipeId = this->getLastInsertedRowId();
|
||||||
|
for (unsigned int i = 0; i < recipe.getIngredients().size(); i++){
|
||||||
|
if (!this->storeRecipeIngredient(recipe.getIngredients()[i], recipeId)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this->storeInstruction(recipe.getInstruction(), recipeId)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->storeImage(recipe.getImage(), recipeId)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri){
|
bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){
|
||||||
|
//First check if the base ingredient has been added to the database. This is done within storeIngredient().
|
||||||
|
ResultTable t = this->executeSQL("SELECT ingredientId FROM ingredient WHERE name='"+ri.getName()+"';");
|
||||||
|
int ingId = 0;
|
||||||
|
if (t.isEmpty()){
|
||||||
|
if (!this->insertInto("ingredient", vector<string>({"foodGroup", "name"}), vector<string>({ri.getFoodGroup(), ri.getName()}))){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ingId = this->getLastInsertedRowId();
|
||||||
|
} else {
|
||||||
|
ingId = std::stoi(t.valueAt(0, 0));
|
||||||
|
}
|
||||||
|
return this->insertInto("recipeIngredient",
|
||||||
|
vector<string>({
|
||||||
|
"ingredientId",
|
||||||
|
"recipeId",
|
||||||
|
"quantity",
|
||||||
|
"unitName",
|
||||||
|
"comment"
|
||||||
|
}),
|
||||||
|
vector<string>({
|
||||||
|
std::to_string(ingId),
|
||||||
|
std::to_string(recipeId),
|
||||||
|
std::to_string(ri.getQuantity()),
|
||||||
|
ri.getUnit().getName(),
|
||||||
|
ri.getComment()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecipeDatabase::storeIngredient(Ingredient ingredient){
|
void RecipeDatabase::storeIngredient(Ingredient ingredient){
|
||||||
ResultTable t = this->executeSQL("SELECT * FROM ingredient WHERE name='"+ingredient.getName()+"';");
|
ResultTable t = this->executeSQL("SELECT * FROM ingredient WHERE name='"+ingredient.getName()+"';");
|
||||||
if (!t.isEmpty()){
|
if (t.isEmpty()){
|
||||||
fprintf(stderr, "Error during storeIngredient: ingredient with name %s already exists.\n", ingredient.getName().c_str());
|
|
||||||
} else {
|
|
||||||
this->insertInto("ingredient", vector<string>({"foodGroup", "name"}), vector<string>({ingredient.getFoodGroup(), ingredient.getName()}));
|
this->insertInto("ingredient", vector<string>({"foodGroup", "name"}), vector<string>({ingredient.getFoodGroup(), ingredient.getName()}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RecipeDatabase::storeInstruction(Instruction instruction, int recipeId){
|
||||||
|
bool success = FileUtils::saveInstruction(recipeId, instruction);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RecipeDatabase::storeImage(QImage image, int recipeId){
|
||||||
|
return FileUtils::saveImage(recipeId, image);
|
||||||
|
}
|
||||||
|
|
||||||
void RecipeDatabase::ensureTablesExist(){
|
void RecipeDatabase::ensureTablesExist(){
|
||||||
//Make sure that foreign keys are enabled.
|
//Make sure that foreign keys are enabled.
|
||||||
this->executeSQL("PRAGMA foreign_keys = ON;");
|
this->executeSQL("PRAGMA foreign_keys = ON;");
|
||||||
|
@ -69,7 +116,7 @@ void RecipeDatabase::ensureTablesExist(){
|
||||||
//RecipeIngredient table.
|
//RecipeIngredient table.
|
||||||
this->executeSQL("CREATE TABLE IF NOT EXISTS recipeIngredient("
|
this->executeSQL("CREATE TABLE IF NOT EXISTS recipeIngredient("
|
||||||
"ingredientId int,"
|
"ingredientId int,"
|
||||||
"recipeId INTEGER PRIMARY KEY,"
|
"recipeId int,"
|
||||||
"quantity real,"
|
"quantity real,"
|
||||||
"unitName varchar,"
|
"unitName varchar,"
|
||||||
"comment varchar,"
|
"comment varchar,"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "model/recipe/recipe.h"
|
#include "model/recipe/recipe.h"
|
||||||
|
#include "utils/fileutils.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -18,11 +19,13 @@ class RecipeDatabase : public Database
|
||||||
RecipeDatabase(string filename);
|
RecipeDatabase(string filename);
|
||||||
|
|
||||||
//Stores a full recipe in the database.
|
//Stores a full recipe in the database.
|
||||||
void storeRecipe(Recipe recipe);
|
bool storeRecipe(Recipe recipe);
|
||||||
|
|
||||||
//SQL Helper methods.
|
//SQL Helper methods.
|
||||||
void storeRecipeIngredient(RecipeIngredient ri);
|
bool storeRecipeIngredient(RecipeIngredient ri, int recipeId);
|
||||||
void storeIngredient(Ingredient ingredient);
|
void storeIngredient(Ingredient ingredient);
|
||||||
|
bool storeInstruction(Instruction instruction, int recipeId);
|
||||||
|
bool storeImage(QImage image, int recipeId);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
//Utility methods.
|
//Utility methods.
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include "fileutils.h"
|
||||||
|
|
||||||
|
namespace FileUtils{
|
||||||
|
|
||||||
|
void ensureAppDataFolderExists(){
|
||||||
|
QDir folder(appDataPath);
|
||||||
|
if (!folder.exists()){
|
||||||
|
folder.mkpath(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveInstruction(int nr, Instruction instruction){
|
||||||
|
ensureAppDataFolderExists();
|
||||||
|
QString filename = appDataPath + QString::fromStdString(std::to_string(nr)) +".html";
|
||||||
|
QFile file(filename);
|
||||||
|
if (file.open(QIODevice::WriteOnly)){
|
||||||
|
QTextStream stream(&file);
|
||||||
|
stream<<instruction.getHTML().c_str()<<endl;
|
||||||
|
file.close();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error opening file: %s to write instruction.\n", filename.toStdString().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction loadInstruction(int nr){
|
||||||
|
QString filename = appDataPath + QString::fromStdString(std::to_string(nr)) + ".html";
|
||||||
|
QFile file(filename);
|
||||||
|
if (!file.exists()){
|
||||||
|
fprintf(stderr, "Instruction Nr: %d does not exist.\n", nr);
|
||||||
|
return Instruction();
|
||||||
|
}
|
||||||
|
if (file.open(QIODevice::ReadOnly)){
|
||||||
|
QTextStream stream(&file);
|
||||||
|
QString s = stream.readAll();
|
||||||
|
file.close();
|
||||||
|
return Instruction(s.toStdString());
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error opening file: %s to read instruction.\n", filename.toStdString().c_str());
|
||||||
|
return Instruction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveImage(int nr, QImage image){
|
||||||
|
QString filename = appDataPath + QString::fromStdString(std::to_string(nr)) + ".png";
|
||||||
|
QFile file(filename);
|
||||||
|
if (file.open(QIODevice::WriteOnly)){
|
||||||
|
image.save(&file, "PNG");
|
||||||
|
file.close();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error saving image to file: %s\n", filename.toStdString().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage loadImage(int nr){
|
||||||
|
QString filename = appDataPath + QString::fromStdString(std::to_string(nr)) + ".png";
|
||||||
|
QImage img(filename);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,53 +5,23 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
#include "model/recipe/instruction.h"
|
#include "model/recipe/instruction.h"
|
||||||
|
|
||||||
namespace FileUtils {
|
namespace FileUtils{
|
||||||
|
|
||||||
QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.recipeDB/";
|
const QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.recipeDB/";
|
||||||
|
|
||||||
void ensureAppDataFolderExists(){
|
void ensureAppDataFolderExists();
|
||||||
QDir folder(appDataPath);
|
|
||||||
if (!folder.exists()){
|
|
||||||
folder.mkpath(".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string saveInstruction(int nr, Instruction instruction){
|
bool saveInstruction(int nr, Instruction instruction);
|
||||||
ensureAppDataFolderExists();
|
|
||||||
QString filename = appDataPath + QString::fromStdString(std::to_string(nr)) +".html";
|
|
||||||
QFile file(filename);
|
|
||||||
if (file.open(QIODevice::WriteOnly)){
|
|
||||||
QTextStream stream(&file);
|
|
||||||
stream<<instruction.getHTML().c_str()<<endl;
|
|
||||||
file.close();
|
|
||||||
return filename.toStdString();
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error opening file: %s to write instruction.\n", filename.toStdString().c_str());
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Instruction loadInstruction(int nr){
|
Instruction loadInstruction(int nr);
|
||||||
QString filename = appDataPath + QString::fromStdString(std::to_string(nr)) + ".html";
|
|
||||||
QFile file(filename);
|
|
||||||
if (!file.exists()){
|
|
||||||
fprintf(stderr, "Instruction Nr: %d does not exist.\n", nr);
|
|
||||||
return Instruction();
|
|
||||||
}
|
|
||||||
if (file.open(QIODevice::ReadOnly)){
|
|
||||||
QTextStream stream(&file);
|
|
||||||
QString s = stream.readAll();
|
|
||||||
file.close();
|
|
||||||
return Instruction(s.toStdString());
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error opening file: %s to read instruction.\n", filename.toStdString().c_str());
|
|
||||||
return Instruction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool saveImage(int nr, QImage image);
|
||||||
|
|
||||||
|
QImage loadImage(int nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FILEUTILS_H
|
#endif // FILEUTILS_H
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef STRINGUTILS_H
|
|
||||||
#define STRINGUTILS_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace StringUtils{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // STRINGUTILS_H
|
|
Loading…
Reference in New Issue