Shift to master. Not done but database abstraction is nearly done. #3

Merged
andrewlalis merged 10 commits from development into master 2018-03-03 09:20:11 +00:00
8 changed files with 146 additions and 72 deletions
Showing only changes of commit cacc75f07d - Show all commits

View File

@ -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 \

View File

@ -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();

View File

@ -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;
}

View File

@ -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,"

View File

@ -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.

64
utils/fileutils.cpp Normal file
View File

@ -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;
}
}

View File

@ -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

View File

@ -1,13 +0,0 @@
#ifndef STRINGUTILS_H
#define STRINGUTILS_H
#include <string>
#include <vector>
namespace StringUtils{
}
#endif // STRINGUTILS_H