Shift to master. Not done but database abstraction is nearly done. #3
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -34,8 +34,16 @@ bool Database::insertInto(string tableName, vector<string> columnNames, vector<s
 | 
			
		|||
	string cols = combineVector(columnNames, ", ");
 | 
			
		||||
	string vals = combineVector(values, ", ");
 | 
			
		||||
	query += cols + ") VALUES (" + vals + ");";
 | 
			
		||||
	this->executeSQL(query);
 | 
			
		||||
	return true;
 | 
			
		||||
	ResultTable t = this->executeSQL(query);
 | 
			
		||||
	return (t.getReturnCode() == SQLITE_DONE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ResultTable Database::selectFrom(string tableName, string columnNames, string conditions){
 | 
			
		||||
	if (columnNames.size() == 0 || tableName.empty()){
 | 
			
		||||
		return ResultTable();
 | 
			
		||||
	}
 | 
			
		||||
	string query = "SELECT " + columnNames + " FROM " + tableName + " WHERE " + conditions + ";";
 | 
			
		||||
	return this->executeSQL(query);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Database::openConnection(){
 | 
			
		||||
| 
						 | 
				
			
			@ -58,18 +66,23 @@ string Database::combineVector(std::vector<string> strings, string mid){
 | 
			
		|||
	if (strings.empty()){
 | 
			
		||||
		return "";
 | 
			
		||||
	}
 | 
			
		||||
	std::string result = "'" + strings[0] + "'";
 | 
			
		||||
	std::string result = surroundString(strings[0], "'");
 | 
			
		||||
	for (std::vector<std::string>::iterator it = strings.begin() + 1; it != strings.end(); ++it){
 | 
			
		||||
		result += mid + "'" + (*it) + "'";
 | 
			
		||||
		result += mid + surroundString((*it), "'");
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
string Database::surroundString(string s, string surround){
 | 
			
		||||
	return surround+s+surround;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Database::tableExists(string tableName){
 | 
			
		||||
	if (tableName.empty() || this->db == NULL || !this->dbIsOpen){
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	ResultTable t = executeSQL("SELECT name FROM sqlite_master WHERE type='table' AND name='"+tableName+"';");
 | 
			
		||||
	ResultTable t = this->selectFrom("sqlite_master", "name", "type='table' AND name='"+tableName+"'");
 | 
			
		||||
	//ResultTable t = executeSQL("SELECT name FROM sqlite_master WHERE type='table' AND name='"+tableName+"';");
 | 
			
		||||
	return !t.isEmpty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,9 +25,14 @@ public:
 | 
			
		|||
	//Executes an SQL string statement in a safe way and returns the result.
 | 
			
		||||
	ResultTable executeSQL(string statement);
 | 
			
		||||
	bool insertInto(string tableName, vector<string> columnNames, vector<string> values);
 | 
			
		||||
	ResultTable selectFrom(string tableName, string columnNames, string conditions);
 | 
			
		||||
 | 
			
		||||
	bool tableExists(string tableName);
 | 
			
		||||
	int getLastInsertedRowId();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	string surroundString(string s, string surround);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //SQL Instance variables.
 | 
			
		||||
    string filename;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,10 +6,11 @@ RecipeDatabase::RecipeDatabase(string filename) : Database(filename){
 | 
			
		|||
 | 
			
		||||
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()+"';");
 | 
			
		||||
	this->executeSQL("BEGIN;");
 | 
			
		||||
	ResultTable t = this->selectFrom("recipe", "*", "name="+surroundString(recipe.getName(), "'"));
 | 
			
		||||
	//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>({
 | 
			
		||||
| 
						 | 
				
			
			@ -29,27 +30,27 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
 | 
			
		|||
		if (success){
 | 
			
		||||
			//If successful, proceed to insert instructions, image, and ingredients.
 | 
			
		||||
			int recipeId = this->getLastInsertedRowId();
 | 
			
		||||
			bool ingredientSuccess = true;
 | 
			
		||||
			for (unsigned int i = 0; i < recipe.getIngredients().size(); i++){
 | 
			
		||||
				if (!this->storeRecipeIngredient(recipe.getIngredients()[i], recipeId)){
 | 
			
		||||
					return false;
 | 
			
		||||
					ingredientSuccess = false;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (!this->storeInstruction(recipe.getInstruction(), recipeId)){
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (!this->storeImage(recipe.getImage(), recipeId)){
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if (ingredientSuccess && this->storeInstruction(recipe.getInstruction(), recipeId) && this->storeImage(recipe.getImage(), recipeId)){
 | 
			
		||||
				this->executeSQL("COMMIT;");
 | 
			
		||||
				return true;
 | 
			
		||||
		} else {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	this->executeSQL("ROLLBACK;");
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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()+"';");
 | 
			
		||||
	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;
 | 
			
		||||
	if (t.isEmpty()){
 | 
			
		||||
		if (!this->insertInto("ingredient", vector<string>({"foodGroup", "name"}), vector<string>({ri.getFoodGroup(), ri.getName()}))){
 | 
			
		||||
| 
						 | 
				
			
			@ -77,15 +78,15 @@ bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void RecipeDatabase::storeIngredient(Ingredient ingredient){
 | 
			
		||||
	ResultTable t = this->executeSQL("SELECT * FROM ingredient WHERE name='"+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()){
 | 
			
		||||
		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;
 | 
			
		||||
	return FileUtils::saveInstruction(recipeId, instruction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RecipeDatabase::storeImage(QImage image, int recipeId){
 | 
			
		||||
| 
						 | 
				
			
			@ -99,12 +100,12 @@ void RecipeDatabase::ensureTablesExist(){
 | 
			
		|||
	this->executeSQL("CREATE TABLE IF NOT EXISTS ingredient("
 | 
			
		||||
					 "ingredientId INTEGER PRIMARY KEY,"
 | 
			
		||||
					 "foodGroup varchar,"
 | 
			
		||||
					 "name varchar);");
 | 
			
		||||
					 "name varchar UNIQUE);");
 | 
			
		||||
	//Recipe table. Each recipe can have at most one instruction, and one image.
 | 
			
		||||
	this->executeSQL("CREATE TABLE IF NOT EXISTS recipe("
 | 
			
		||||
					 "recipeId INTEGER PRIMARY KEY,"
 | 
			
		||||
					 "createdDate date,"
 | 
			
		||||
					 "name varchar,"
 | 
			
		||||
					 "name varchar UNIQUE,"
 | 
			
		||||
					 "cookTime time,"
 | 
			
		||||
					 "prepTime time,"
 | 
			
		||||
					 "servingCount real);");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,8 @@ class RecipeDatabase : public Database
 | 
			
		|||
		void storeIngredient(Ingredient ingredient);
 | 
			
		||||
		bool storeInstruction(Instruction instruction, int recipeId);
 | 
			
		||||
		bool storeImage(QImage image, int recipeId);
 | 
			
		||||
 | 
			
		||||
		vector<Recipe> retrieveRecipe(string name);
 | 
			
		||||
	private:
 | 
			
		||||
 | 
			
		||||
		//Utility methods.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ void ResultTable::extractData(sqlite3_stmt *stmt){
 | 
			
		|||
		processRow(stmt);
 | 
			
		||||
		res = sqlite3_step(stmt);
 | 
			
		||||
	}
 | 
			
		||||
	this->queryCode = res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ResultTable::processRow(sqlite3_stmt *stmt){
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +52,10 @@ string ResultTable::valueAt(unsigned int row, unsigned int col){
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ResultTable::getReturnCode(){
 | 
			
		||||
	return this->queryCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int ResultTable::columnCount(){
 | 
			
		||||
	if (this->isEmpty()){
 | 
			
		||||
		return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,10 +27,12 @@ class ResultTable
 | 
			
		|||
 | 
			
		||||
		bool isEmpty();
 | 
			
		||||
		string valueAt(unsigned int row, unsigned int col);
 | 
			
		||||
		int getReturnCode();
 | 
			
		||||
		unsigned int columnCount();
 | 
			
		||||
		unsigned int rowCount();
 | 
			
		||||
	private:
 | 
			
		||||
		vector<vector<string>> values;
 | 
			
		||||
		int queryCode;
 | 
			
		||||
 | 
			
		||||
		//Utility methods.
 | 
			
		||||
		string convertToString(sqlite3_value* val);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue