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
9 changed files with 107 additions and 16 deletions
Showing only changes of commit 446ff8f5ba - Show all commits

View File

@ -30,11 +30,10 @@ int main(int argc, char *argv[])
bool success = recipeDB.storeRecipe(rec); bool success = recipeDB.storeRecipe(rec);
printf("Storage successful: %d\n", success); printf("Storage successful: %d\n", success);
recipeDB.executeSQL("SELECT * FROM recipeIngredient;").printData();
Recipe reloadRec = recipeDB.retrieveRecipe("Example"); Recipe reloadRec = recipeDB.retrieveRecipe("Example");
reloadRec.print();
w.loadFromRecipe(rec); w.loadFromRecipe(reloadRec);
return a.exec(); return a.exec();
} }

View File

@ -8,7 +8,6 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
///TODO: Implement this in a smart way using transaction. ///TODO: Implement this in a smart way using transaction.
this->executeSQL("BEGIN;"); this->executeSQL("BEGIN;");
ResultTable t = this->selectFrom("recipe", "*", "name="+surroundString(recipe.getName(), "'")); ResultTable t = this->selectFrom("recipe", "*", "name="+surroundString(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());
} else { } else {
@ -28,7 +27,7 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
std::to_string(recipe.getServings()) std::to_string(recipe.getServings())
})); }));
if (success){ if (success){
//If successful, proceed to insert instructions, image, and ingredients. //If successful, proceed to insert instructions, image, and ingredients, and tags.
int recipeId = this->getLastInsertedRowId(); int recipeId = this->getLastInsertedRowId();
bool ingredientSuccess = true; bool ingredientSuccess = true;
for (unsigned int i = 0; i < recipe.getIngredients().size(); i++){ for (unsigned int i = 0; i < recipe.getIngredients().size(); i++){
@ -37,7 +36,10 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
break; break;
} }
} }
if (ingredientSuccess && this->storeInstruction(recipe.getInstruction(), recipeId) && this->storeImage(recipe.getImage(), recipeId)){ if (ingredientSuccess &&
this->storeInstruction(recipe.getInstruction(), recipeId) &&
this->storeImage(recipe.getImage(), recipeId) &&
this->storeTags(recipe.getTags(), recipeId)){
this->executeSQL("COMMIT;"); this->executeSQL("COMMIT;");
return true; return true;
} }
@ -50,7 +52,6 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){ bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){
//First check if the base ingredient has been added to the database. This is done within storeIngredient(). //First check if the base ingredient has been added to the database. This is done within storeIngredient().
ResultTable t = this->selectFrom("ingredient", "ingredientId", "name="+surroundString(ri.getName(), "'")); ResultTable t = this->selectFrom("ingredient", "ingredientId", "name="+surroundString(ri.getName(), "'"));
//ResultTable t = this->executeSQL("SELECT ingredientId FROM ingredient WHERE name='"+ri.getName()+"';");
int ingId = 0; int ingId = 0;
if (t.isEmpty()){ if (t.isEmpty()){
if (!this->insertInto("ingredient", vector<string>({"foodGroup", "name"}), vector<string>({ri.getFoodGroup(), ri.getName()}))){ if (!this->insertInto("ingredient", vector<string>({"foodGroup", "name"}), vector<string>({ri.getFoodGroup(), ri.getName()}))){
@ -79,7 +80,6 @@ bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){
void RecipeDatabase::storeIngredient(Ingredient ingredient){ void RecipeDatabase::storeIngredient(Ingredient ingredient){
ResultTable t = this->selectFrom("ingredient", "*", "name="+surroundString(ingredient.getName(), "'")); ResultTable t = this->selectFrom("ingredient", "*", "name="+surroundString(ingredient.getName(), "'"));
//ResultTable t = this->executeSQL("SELECT * FROM ingredient WHERE name='"+ingredient.getName()+"';");
if (t.isEmpty()){ if (t.isEmpty()){
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()}));
} }
@ -93,6 +93,24 @@ bool RecipeDatabase::storeImage(QImage image, int recipeId){
return FileUtils::saveImage(recipeId, image); return FileUtils::saveImage(recipeId, image);
} }
bool RecipeDatabase::storeTags(vector<RecipeTag> tags, int recipeId){
for (vector<RecipeTag>::iterator it = tags.begin(); it != tags.end(); ++it){
bool s = this->insertInto("recipeTag",
vector<string>({
"recipeId",
"tagName"
}),
vector<string>({
std::to_string(recipeId),
(*it).getValue()
}));
if (!s){
return false;
}
}
return true;
}
Recipe RecipeDatabase::retrieveRecipe(string name){ Recipe RecipeDatabase::retrieveRecipe(string name){
ResultTable t = this->selectFrom("recipe", "*", "name="+surroundString(name, "'")); ResultTable t = this->selectFrom("recipe", "*", "name="+surroundString(name, "'"));
if (t.isEmpty()){ if (t.isEmpty()){
@ -100,12 +118,39 @@ Recipe RecipeDatabase::retrieveRecipe(string name){
return Recipe(); return Recipe();
} }
t.printData(); t.printData();
return Recipe(); Recipe r;
int id = std::stoi(t.valueAt(0, 0));
r.setName(t.valueAt(0, 1));
r.setCreatedDate(QDate::fromString(QString::fromStdString(t.valueAt(0, 2))));
r.setPrepTime(QTime::fromString(QString::fromStdString(t.valueAt(0, 3))));
r.setCookTime(QTime::fromString(QString::fromStdString(t.valueAt(0, 4))));
r.setServings(std::stof(t.valueAt(0, 5)));
r.setInstruction(FileUtils::loadInstruction(id));
r.setImage(FileUtils::loadImage(id));
r.setIngredients(this->retrieveRecipeIngredients(id));
return r;
}
vector<RecipeIngredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId){
ResultTable t = this->executeSQL("SELECT ingredient.name, ingredient.foodGroup, recipeIngredient.quantity, recipeIngredient.unitName, recipeIngredient.comment "
"FROM ingredient "
"INNER JOIN recipeIngredient "
"ON ingredient.ingredientId = recipeIngredient.ingredientId "
"AND recipeIngredient.recipeId = "+std::to_string(recipeId)+";");
t.printData();
vector<RecipeIngredient> ings;
for (unsigned int row = 0; row < t.rowCount(); row++){
RecipeIngredient r(t.valueAt(row, 0), t.valueAt(row, 1), std::stof(t.valueAt(row, 2)), UnitOfMeasure(t.valueAt(row, 3)));
ings.push_back(r);
}
return ings;
} }
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;");
this->executeSQL("BEGIN;");
//Ingredients table. //Ingredients table.
this->executeSQL("CREATE TABLE IF NOT EXISTS ingredient(" this->executeSQL("CREATE TABLE IF NOT EXISTS ingredient("
"ingredientId INTEGER PRIMARY KEY," "ingredientId INTEGER PRIMARY KEY,"
@ -114,14 +159,14 @@ void RecipeDatabase::ensureTablesExist(){
//Recipe table. Each recipe can have at most one instruction, and one image. //Recipe table. Each recipe can have at most one instruction, and one image.
this->executeSQL("CREATE TABLE IF NOT EXISTS recipe(" this->executeSQL("CREATE TABLE IF NOT EXISTS recipe("
"recipeId INTEGER PRIMARY KEY," "recipeId INTEGER PRIMARY KEY,"
"createdDate date,"
"name varchar UNIQUE," "name varchar UNIQUE,"
"cookTime time," "createdDate date,"
"prepTime time," "prepTime time,"
"cookTime time,"
"servingCount real);"); "servingCount real);");
//Recipe tags table. //Recipe tags table.
this->executeSQL("CREATE TABLE IF NOT EXISTS recipeTag(" this->executeSQL("CREATE TABLE IF NOT EXISTS recipeTag("
"recipeId INTEGER PRIMARY KEY," "recipeId int,"
"tagName varchar," "tagName varchar,"
"FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));"); "FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));");
//RecipeIngredient table. //RecipeIngredient table.
@ -133,4 +178,5 @@ void RecipeDatabase::ensureTablesExist(){
"comment varchar," "comment varchar,"
"FOREIGN KEY (ingredientId) REFERENCES ingredient(ingredientId)," "FOREIGN KEY (ingredientId) REFERENCES ingredient(ingredientId),"
"FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));"); "FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));");
this->executeSQL("COMMIT;");
} }

View File

@ -26,8 +26,10 @@ class RecipeDatabase : public Database
void storeIngredient(Ingredient ingredient); void storeIngredient(Ingredient ingredient);
bool storeInstruction(Instruction instruction, int recipeId); bool storeInstruction(Instruction instruction, int recipeId);
bool storeImage(QImage image, int recipeId); bool storeImage(QImage image, int recipeId);
bool storeTags(vector<RecipeTag> tags, int recipeId);
Recipe retrieveRecipe(string name); Recipe retrieveRecipe(string name);
vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
private: private:
//Utility methods. //Utility methods.

View File

@ -9,7 +9,11 @@ RecipeIngredient::RecipeIngredient(Ingredient i, float quantity, UnitOfMeasure u
setName(i.getName()); setName(i.getName());
setFoodGroup(i.getFoodGroup()); setFoodGroup(i.getFoodGroup());
setQuantity(quantity); setQuantity(quantity);
setUnit(unit); setUnit(unit);
}
RecipeIngredient::RecipeIngredient(){
} }
float RecipeIngredient::getQuantity() const{ float RecipeIngredient::getQuantity() const{

View File

@ -19,6 +19,7 @@ public:
RecipeIngredient(string name, string foodGroup, float quantity, UnitOfMeasure unit); RecipeIngredient(string name, string foodGroup, float quantity, UnitOfMeasure unit);
//Constructor using data from a child ingredient. //Constructor using data from a child ingredient.
RecipeIngredient(Ingredient i, float quantity, UnitOfMeasure unit); RecipeIngredient(Ingredient i, float quantity, UnitOfMeasure unit);
RecipeIngredient();
//Getters //Getters
float getQuantity() const; float getQuantity() const;

View File

@ -3,7 +3,14 @@
UnitOfMeasure::UnitOfMeasure(string name, string plural, string abbreviation){ UnitOfMeasure::UnitOfMeasure(string name, string plural, string abbreviation){
this->name = name; this->name = name;
this->plural = plural; this->plural = plural;
this->abbreviation = abbreviation; this->abbreviation = abbreviation;
}
UnitOfMeasure::UnitOfMeasure(string name){
this->name = name;
this->plural = name + "s";
this->abbreviation = "NULL";
///TODO: Make actual guessing of this stuff.
} }
UnitOfMeasure::UnitOfMeasure() : UnitOfMeasure::UnitOfMeasure("", "", ""){ UnitOfMeasure::UnitOfMeasure() : UnitOfMeasure::UnitOfMeasure("", "", ""){

View File

@ -14,6 +14,8 @@ class UnitOfMeasure
public: public:
//Full constructor. //Full constructor.
UnitOfMeasure(string name, string plural, string abbreviation); UnitOfMeasure(string name, string plural, string abbreviation);
//Attempt to guess unit from just a string.
UnitOfMeasure(string name);
//Constructor with default values. //Constructor with default values.
UnitOfMeasure(); UnitOfMeasure();

View File

@ -29,7 +29,11 @@ Instruction Recipe::getInstruction() const{
} }
QImage Recipe::getImage() const{ QImage Recipe::getImage() const{
return this->image; return this->image;
}
vector<RecipeTag> Recipe::getTags() const{
return this->tags;
} }
QDate Recipe::getCreatedDate() const{ QDate Recipe::getCreatedDate() const{
@ -89,5 +93,29 @@ void Recipe::setCookTime(QTime newTime){
} }
void Recipe::setServings(float newServingsCount){ void Recipe::setServings(float newServingsCount){
this->servings = newServingsCount; this->servings = newServingsCount;
}
void Recipe::print(){
printf("Recipe: %s, Created on: %s, Prep time: %s, Cook time: %s, Serves: %f\n",
this->name.c_str(),
this->createdDate.toString().toStdString().c_str(),
this->prepTime.toString().toStdString().c_str(),
this->cookTime.toString().toStdString().c_str(),
this->servings);
printf("\tInstruction: %s\n", this->instruction.getHTML().c_str());
printf("\tIngredients:\n");
for (vector<RecipeIngredient>::iterator it = this->ingredients.begin(); it != this->ingredients.end(); ++it){
RecipeIngredient ri = *it;
printf("\t\t%s, Food Group: %s, Quantity: %f, Unit: %s\n",
ri.getName().c_str(),
ri.getFoodGroup().c_str(),
ri.getQuantity(),
ri.getUnit().getName().c_str());
}
printf("\tTags:\n");
for (vector<RecipeTag>::iterator it = this->tags.begin(); it != this->tags.end(); ++it){
RecipeTag t = *it;
printf("\t\t%s\n", t.getValue().c_str());
}
} }

View File

@ -58,6 +58,8 @@ public:
void setPrepTime(QTime newTime); void setPrepTime(QTime newTime);
void setCookTime(QTime newTime); void setCookTime(QTime newTime);
void setServings(float newServingsCount); void setServings(float newServingsCount);
void print();
private: private:
//Main information. //Main information.
string name; //The name of the recipe. string name; //The name of the recipe.