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 \
 | 
			
		||||
    SQLite/sqlite3.c \
 | 
			
		||||
    model/database/resulttable.cpp \
 | 
			
		||||
    model/database/recipedatabase.cpp
 | 
			
		||||
    model/database/recipedatabase.cpp \
 | 
			
		||||
    utils/fileutils.cpp
 | 
			
		||||
 | 
			
		||||
HEADERS  += model/recipe/instruction.h \
 | 
			
		||||
    model/recipe/recipe.h \
 | 
			
		||||
| 
						 | 
				
			
			@ -39,8 +40,7 @@ HEADERS  += model/recipe/instruction.h \
 | 
			
		|||
    SQLite/sqlite3ext.h \
 | 
			
		||||
    model/database/resulttable.h \
 | 
			
		||||
    model/database/recipedatabase.h \
 | 
			
		||||
    utils/fileutils.h \
 | 
			
		||||
    utils/stringutils.h
 | 
			
		||||
    utils/fileutils.h
 | 
			
		||||
 | 
			
		||||
LIBS += -ldl \
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								main.cpp
								
								
								
								
							
							
						
						
									
										16
									
								
								main.cpp
								
								
								
								
							| 
						 | 
				
			
			@ -3,7 +3,6 @@
 | 
			
		|||
 | 
			
		||||
#include "model/database/database.h"
 | 
			
		||||
#include "model/database/recipedatabase.h"
 | 
			
		||||
#include "utils/fileutils.h"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -14,12 +13,12 @@ int main(int argc, char *argv[])
 | 
			
		|||
	//TESTING CODE
 | 
			
		||||
 | 
			
		||||
	RecipeDatabase recipeDB("recipes");
 | 
			
		||||
	recipeDB.storeIngredient(Ingredient("Apple", "Fruit"));
 | 
			
		||||
	recipeDB.storeIngredient(Ingredient("Corn", "Vegetable"));
 | 
			
		||||
	recipeDB.storeIngredient(Ingredient("Lettuce", "Vegetable"));
 | 
			
		||||
	recipeDB.storeIngredient(Ingredient("Carrot", "Vegetable"));
 | 
			
		||||
//	recipeDB.storeIngredient(Ingredient("Apple", "Fruit"));
 | 
			
		||||
//	recipeDB.storeIngredient(Ingredient("Corn", "Vegetable"));
 | 
			
		||||
//	recipeDB.storeIngredient(Ingredient("Lettuce", "Vegetable"));
 | 
			
		||||
//	recipeDB.storeIngredient(Ingredient("Carrot", "Vegetable"));
 | 
			
		||||
 | 
			
		||||
	recipeDB.executeSQL("SELECT * FROM ingredient;").printData();
 | 
			
		||||
//	recipeDB.executeSQL("SELECT * FROM ingredient;").printData();
 | 
			
		||||
 | 
			
		||||
	//TESTING CODE
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	bool success = recipeDB.storeRecipe(rec);
 | 
			
		||||
	printf("Storage successful: %d\n", success);
 | 
			
		||||
 | 
			
		||||
	recipeDB.executeSQL("SELECT * FROM recipeIngredient;").printData();
 | 
			
		||||
 | 
			
		||||
	w.loadFromRecipe(rec);
 | 
			
		||||
 | 
			
		||||
	return a.exec();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,6 @@ bool Database::insertInto(string tableName, vector<string> columnNames, vector<s
 | 
			
		|||
	string cols = combineVector(columnNames, ", ");
 | 
			
		||||
	string vals = combineVector(values, ", ");
 | 
			
		||||
	query += cols + ") VALUES (" + vals + ");";
 | 
			
		||||
	printf("Executing query: %s\n", query.c_str());
 | 
			
		||||
	this->executeSQL(query);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,11 +4,12 @@ RecipeDatabase::RecipeDatabase(string filename) : Database(filename){
 | 
			
		|||
	this->ensureTablesExist();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecipeDatabase::storeRecipe(Recipe recipe){
 | 
			
		||||
bool RecipeDatabase::storeRecipe(Recipe recipe){
 | 
			
		||||
	///TODO: Implement this in a smart way using transaction.
 | 
			
		||||
	ResultTable t = this->executeSQL("SELECT * FROM recipe WHERE name='"+recipe.getName()+"';");
 | 
			
		||||
	if (!t.isEmpty()){
 | 
			
		||||
		fprintf(stderr, "Error storing recipe: Recipe with name %s already exists.\n", recipe.getName().c_str());
 | 
			
		||||
		return false;
 | 
			
		||||
	} else {
 | 
			
		||||
		bool success = this->insertInto("recipe",
 | 
			
		||||
						 vector<string>({
 | 
			
		||||
| 
						 | 
				
			
			@ -27,24 +28,70 @@ void RecipeDatabase::storeRecipe(Recipe recipe){
 | 
			
		|||
										}));
 | 
			
		||||
		if (success){
 | 
			
		||||
			//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){
 | 
			
		||||
	ResultTable t = this->executeSQL("SELECT * FROM ingredient WHERE name='"+ingredient.getName()+"';");
 | 
			
		||||
	if (!t.isEmpty()){
 | 
			
		||||
		fprintf(stderr, "Error during storeIngredient: ingredient with name %s already exists.\n", ingredient.getName().c_str());
 | 
			
		||||
	} else {
 | 
			
		||||
	if (t.isEmpty()){
 | 
			
		||||
		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(){
 | 
			
		||||
	//Make sure that foreign keys are enabled.
 | 
			
		||||
	this->executeSQL("PRAGMA foreign_keys = ON;");
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +116,7 @@ void RecipeDatabase::ensureTablesExist(){
 | 
			
		|||
	//RecipeIngredient table.
 | 
			
		||||
	this->executeSQL("CREATE TABLE IF NOT EXISTS recipeIngredient("
 | 
			
		||||
					 "ingredientId int,"
 | 
			
		||||
					 "recipeId INTEGER PRIMARY KEY,"
 | 
			
		||||
					 "recipeId int,"
 | 
			
		||||
					 "quantity real,"
 | 
			
		||||
					 "unitName varchar,"
 | 
			
		||||
					 "comment varchar,"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
 | 
			
		||||
#include "database.h"
 | 
			
		||||
#include "model/recipe/recipe.h"
 | 
			
		||||
#include "utils/fileutils.h"
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,11 +19,13 @@ class RecipeDatabase : public Database
 | 
			
		|||
		RecipeDatabase(string filename);
 | 
			
		||||
 | 
			
		||||
		//Stores a full recipe in the database.
 | 
			
		||||
		void storeRecipe(Recipe recipe);
 | 
			
		||||
		bool storeRecipe(Recipe recipe);
 | 
			
		||||
 | 
			
		||||
		//SQL Helper methods.
 | 
			
		||||
		void storeRecipeIngredient(RecipeIngredient ri);
 | 
			
		||||
		bool storeRecipeIngredient(RecipeIngredient ri, int recipeId);
 | 
			
		||||
		void storeIngredient(Ingredient ingredient);
 | 
			
		||||
		bool storeInstruction(Instruction instruction, int recipeId);
 | 
			
		||||
		bool storeImage(QImage image, int recipeId);
 | 
			
		||||
	private:
 | 
			
		||||
 | 
			
		||||
		//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 <QDir>
 | 
			
		||||
#include <QTextStream>
 | 
			
		||||
#include <QImage>
 | 
			
		||||
 | 
			
		||||
#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(){
 | 
			
		||||
		QDir folder(appDataPath);
 | 
			
		||||
		if (!folder.exists()){
 | 
			
		||||
			folder.mkpath(".");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	void ensureAppDataFolderExists();
 | 
			
		||||
 | 
			
		||||
	string 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 "";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	bool saveInstruction(int nr, Instruction instruction);
 | 
			
		||||
 | 
			
		||||
	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();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	Instruction loadInstruction(int nr);
 | 
			
		||||
 | 
			
		||||
	bool saveImage(int nr, QImage image);
 | 
			
		||||
 | 
			
		||||
	QImage loadImage(int nr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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