Compare commits
9 Commits
03b1250006
...
0b348e8c10
Author | SHA1 | Date | |
---|---|---|---|
0b348e8c10 | |||
f68a8b45a5 | |||
feed35d8c8 | |||
db0b607546 | |||
d8a140e913 | |||
a1e3322576 | |||
802f3bfcc0 | |||
5873ceb627 | |||
5bcc598880 |
152
README.md
152
README.md
@ -1,11 +1,139 @@
|
|||||||
# Menu Helper
|
# Menu-Helper
|
||||||
|
|
||||||
A program to manage a database of recipes and help you to pick out meals based
|
A program to manage a database of recipes and help you to pick out meals based
|
||||||
on filters of ingredients and tags.
|
on filters of ingredients and tags.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Ensure the `XDG_DATA_HOME` variable is set (e.g. to `$HOME/.local/share`).
|
Ensure the `XDG_DATA_HOME` variable is set (e.g. to `$HOME/.local/share`) and
|
||||||
|
that you have installed the SQLite3 library.
|
||||||
|
|
||||||
|
Upon first execution of any command, the program will automatically create the
|
||||||
|
database.
|
||||||
|
|
||||||
|
### Adding New Recipes
|
||||||
|
|
||||||
|
The first thing you're probably going to want to do is to add a new recipe to
|
||||||
|
your database. If this database hasn't been created already then the program
|
||||||
|
will do it automatically. This is done via the `add` subcommand, which will
|
||||||
|
query you about the different attributes you want for your recipe, looking
|
||||||
|
something like the following:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ menu-helper add
|
||||||
|
Name: Linguine Scampi
|
||||||
|
Description: A lemony Italian pasta dish.
|
||||||
|
Ingredients (comma separated): linguine,shrimp,garlic,parsley,lemon
|
||||||
|
Tags (comma separated): italian,lunch
|
||||||
|
Creating database in /home/nicolas/.local/share/menu-helper/recipes.db
|
||||||
|
```
|
||||||
|
|
||||||
|
This will have created your recipe within the database. That last line there is
|
||||||
|
merely informative, telling you that the database did not exist and it is not
|
||||||
|
being created; if you had a database already and it isn't being found, ensure
|
||||||
|
that your `XDG_DATA_HOME` environment variable is properly set.
|
||||||
|
|
||||||
|
### Querying Recipes
|
||||||
|
|
||||||
|
#### Filtering
|
||||||
|
|
||||||
|
Once a recipe or two have been added to your database you may now query them
|
||||||
|
filtering based on ingredients and tags. This is done via the `list` command,
|
||||||
|
which takes two kinds of arguments, both optional:
|
||||||
|
|
||||||
|
- `-i <list>`: Comma-separated list of the ingredients to look for.
|
||||||
|
- `-t <list>`: Comma-separated list of the tags to look for.
|
||||||
|
|
||||||
|
If neither is specified then all recipes will be listed with their respective
|
||||||
|
ID, name, and description:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ menu-helper list
|
||||||
|
1 | Linguine Scampi | A lemony Italian pasta dish.
|
||||||
|
2 | Garlic Soup | A simple monastic soup for cold winters.
|
||||||
|
```
|
||||||
|
|
||||||
|
However, when one of these arguments is used it filters recipes to only show
|
||||||
|
those which include __all__ the ingredients and tags specified:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ menu-helper list -i linguine
|
||||||
|
1 | Linguine Scampi | A lemony Italian pasta dish.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Recipe Information
|
||||||
|
|
||||||
|
The IDs shown in the queries above now become useful for the rest of
|
||||||
|
Menu-Helper functionality. If you wish to query all stored information about a
|
||||||
|
given recipe, this is where you can use the `info` subcommand with the relevant
|
||||||
|
ID:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ menu-helper info 2
|
||||||
|
Name: Garlic Soup
|
||||||
|
Description: A simple monastic soup for cold winters.
|
||||||
|
ID: 2
|
||||||
|
|
||||||
|
Ingredients:
|
||||||
|
- garlic
|
||||||
|
- bread
|
||||||
|
- egg
|
||||||
|
|
||||||
|
Tags:
|
||||||
|
- soup
|
||||||
|
- dinner
|
||||||
|
- simple
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Removing Recipes
|
||||||
|
|
||||||
|
If you end up desiring to remove a recipe for whatever reason, you can do so by
|
||||||
|
using the `del` subcommand with the recipe's corresponding ID:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ menu-helper del 2
|
||||||
|
$ menu-helper list
|
||||||
|
1 | Linguine Scampi | A lemony Italian pasta dish.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modifying Recipe Ingredients/Tags
|
||||||
|
|
||||||
|
If there are ingredients/tags which you forgot to add to a recipe, or that you
|
||||||
|
added erringly, you can correct this with the following commands:
|
||||||
|
|
||||||
|
- `add-ingr <id> <list>`: Add list of comma-separated ingredients `list` to
|
||||||
|
recipe with ID `id`.
|
||||||
|
- `rm-ingr <id> <list>`: Remove list of comma-separated ingredients `list` from
|
||||||
|
recipe with ID `id`.
|
||||||
|
- `add-tag <id> <list>`: Add list of comma-separated tags `list` to recipe with
|
||||||
|
ID `id`.
|
||||||
|
- `rm-tag <id> <list>`: Remove list of comma-separated tags `list` from recipe
|
||||||
|
with ID `id`.
|
||||||
|
|
||||||
|
For example, we forgot to add the useful tag to our first recipe (Linguine
|
||||||
|
Scampi) that it is a pasta dish. We can do this with the following command:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ menu-helper add-tag 1 pasta
|
||||||
|
$ menu-helper info 1
|
||||||
|
Name: Linguine Scampi
|
||||||
|
Description: A lemony Italian pasta dish.
|
||||||
|
ID: 1
|
||||||
|
|
||||||
|
Ingredients:
|
||||||
|
- linguine
|
||||||
|
- shrimp
|
||||||
|
- garlic
|
||||||
|
- parsley
|
||||||
|
- lemon
|
||||||
|
|
||||||
|
Tags:
|
||||||
|
- italian
|
||||||
|
- lunch
|
||||||
|
- pasta
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
@ -15,7 +143,25 @@ To build the program you will require the following dependencies:
|
|||||||
- SQLite3 C/C++ library
|
- SQLite3 C/C++ library
|
||||||
- Make
|
- Make
|
||||||
|
|
||||||
Once installed, compile the project with the `make` command.
|
Once installed, compile the project with the `make` command. To install simply
|
||||||
|
run the `make install` command, optionally appending `PREFIX=...` to change the
|
||||||
|
default directory of installation (i.e. `/usr/local/...`).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
If you find any issues, feel free to report them on GitHub or send me an E-Mail
|
||||||
|
(see my website/profile for the address). I will add these issues to my personal
|
||||||
|
Gitea page and (unless specified otherwise) mention you as the person who found
|
||||||
|
the issue.
|
||||||
|
|
||||||
|
For patches/pull requests, if you open a PR on GitHub I will likely not merge
|
||||||
|
directly but instead apply the patches locally (via Git patches, conserving
|
||||||
|
authorship), push them to my Gitea repository, which will finally be mirrored to
|
||||||
|
GitHub. However, you can save me a bit of work by just sending me the Git
|
||||||
|
patches directly (via E-Mail).
|
||||||
|
|
||||||
|
If you're looking for a way to contribute, consider having a look at my [To-Do
|
||||||
|
list](/TODO.md) for the project.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
10
TODO.md
Normal file
10
TODO.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# To-Do List
|
||||||
|
|
||||||
|
- [ ] Add more safeguards to avoid bad usage.
|
||||||
|
- [ ] Create a man page.
|
||||||
|
- [ ] Add more documentation to `help` subcommand.
|
||||||
|
- [ ] Add import/export functionality.
|
||||||
|
- [ ] Properly align output columns from `list` subcommand.
|
||||||
|
- [ ] Add feature for editing recipe name and description.
|
||||||
|
- [ ] Name
|
||||||
|
- [ ] Description
|
@ -25,18 +25,26 @@
|
|||||||
enum cmd_id {
|
enum cmd_id {
|
||||||
CMD_UNKNOWN = 0,
|
CMD_UNKNOWN = 0,
|
||||||
CMD_ADD,
|
CMD_ADD,
|
||||||
CMD_LIST,
|
|
||||||
CMD_DEL,
|
CMD_DEL,
|
||||||
|
CMD_LIST,
|
||||||
CMD_INFO,
|
CMD_INFO,
|
||||||
|
CMD_ADD_INGR,
|
||||||
|
CMD_RM_INGR,
|
||||||
|
CMD_ADD_TAG,
|
||||||
|
CMD_RM_TAG,
|
||||||
CMD_HELP,
|
CMD_HELP,
|
||||||
CMD_VERSION,
|
CMD_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<enum cmd_id, std::vector<std::string>> commands = {
|
static const std::map<enum cmd_id, std::vector<std::string>> commands = {
|
||||||
{ CMD_ADD, {"add", "new"} },
|
{ CMD_ADD, {"add", "new"} },
|
||||||
{ CMD_LIST, {"list", "ls"} },
|
|
||||||
{ CMD_DEL, {"del", "rm"} },
|
{ CMD_DEL, {"del", "rm"} },
|
||||||
|
{ CMD_LIST, {"list", "ls"} },
|
||||||
{ CMD_INFO, {"info", "i"} },
|
{ CMD_INFO, {"info", "i"} },
|
||||||
|
{ CMD_ADD_INGR, {"add-ingr"} },
|
||||||
|
{ CMD_RM_INGR, {"rm-ingr"} },
|
||||||
|
{ CMD_ADD_TAG, {"add-tag"} },
|
||||||
|
{ CMD_RM_TAG, {"rm-tag"} },
|
||||||
{ CMD_HELP, {"help", "-h", "--help"} },
|
{ CMD_HELP, {"help", "-h", "--help"} },
|
||||||
{ CMD_VERSION, {"version", "-v", "--version"} },
|
{ CMD_VERSION, {"version", "-v", "--version"} },
|
||||||
};
|
};
|
||||||
@ -55,9 +63,13 @@ static inline void print_help(void) {
|
|||||||
|
|
||||||
std::cout << "COMMANDS:\n"
|
std::cout << "COMMANDS:\n"
|
||||||
"\tadd, new Add a new recipe to the database.\n"
|
"\tadd, new Add a new recipe to the database.\n"
|
||||||
"\tlist, ls List recipes with filters.\n"
|
|
||||||
"\tdel, rm Delete recipe by ID.\n"
|
"\tdel, rm Delete recipe by ID.\n"
|
||||||
|
"\tlist, ls List recipes with filters.\n"
|
||||||
"\tinfo Show recipe information.\n"
|
"\tinfo Show recipe information.\n"
|
||||||
|
"\tadd-ingr Add ingredient to a recipe.\n"
|
||||||
|
"\trm-ingr Remove ingredient from a recipe.\n"
|
||||||
|
"\tadd-tag Add tag to a recipe.\n"
|
||||||
|
"\trm-tag Remove tag from a recipe.\n"
|
||||||
"\thelp, -h, --help Show this help information.\n"
|
"\thelp, -h, --help Show this help information.\n"
|
||||||
"\tversion, -v, --version Show version information.\n"
|
"\tversion, -v, --version Show version information.\n"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
114
src/cmd.cpp
114
src/cmd.cpp
@ -167,3 +167,117 @@ int cmd_info(const int id) {
|
|||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cmd_add_ingr(const int recipe_id, const char *ingredients) {
|
||||||
|
db db;
|
||||||
|
std::vector<std::string> ingr_list = split(ingredients, ",");
|
||||||
|
|
||||||
|
db.open();
|
||||||
|
if(not db.recipe_exists(recipe_id)) {
|
||||||
|
std::cerr << "Recipe with ID " << recipe_id << " does not exist." << std::endl;
|
||||||
|
db.close();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &i : ingr_list) {
|
||||||
|
int ingr_id;
|
||||||
|
trim(i);
|
||||||
|
|
||||||
|
if(not db.ingredient_exists(i))
|
||||||
|
ingr_id = db.add_ingredient(i);
|
||||||
|
else
|
||||||
|
ingr_id = db.get_ingredient_id(i);
|
||||||
|
|
||||||
|
db.conn_recipe_ingredient(recipe_id, ingr_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_rm_ingr(const int recipe_id, const char *ingredients) {
|
||||||
|
db db;
|
||||||
|
std::vector<std::string> ingr_list = split(ingredients, ",");
|
||||||
|
|
||||||
|
db.open();
|
||||||
|
if(not db.recipe_exists(recipe_id)) {
|
||||||
|
std::cerr << "Recipe with ID " << recipe_id << " does not exist." << std::endl;
|
||||||
|
db.close();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &i : ingr_list) {
|
||||||
|
int ingr_id;
|
||||||
|
trim(i);
|
||||||
|
|
||||||
|
if(not db.ingredient_exists(i)) {
|
||||||
|
std::cerr << "Could not find ingredient '" << i << "'. Skipping!" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ingr_id = db.get_ingredient_id(i);
|
||||||
|
db.disconn_recipe_ingredient(recipe_id, ingr_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_add_tag(const int recipe_id, const char *tags) {
|
||||||
|
db db;
|
||||||
|
std::vector<std::string> tag_list = split(tags, ",");
|
||||||
|
|
||||||
|
db.open();
|
||||||
|
if(not db.recipe_exists(recipe_id)) {
|
||||||
|
std::cerr << "Recipe with ID " << recipe_id << " does not exist." << std::endl;
|
||||||
|
db.close();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &i : tag_list) {
|
||||||
|
int tag_id;
|
||||||
|
trim(i);
|
||||||
|
|
||||||
|
if(not db.tag_exists(i))
|
||||||
|
tag_id = db.add_tag(i);
|
||||||
|
else
|
||||||
|
tag_id = db.get_ingredient_id(i);
|
||||||
|
|
||||||
|
db.conn_recipe_tag(recipe_id, tag_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_rm_tag(const int recipe_id, const char *tags) {
|
||||||
|
db db;
|
||||||
|
std::vector<std::string> tag_list = split(tags, ",");
|
||||||
|
|
||||||
|
db.open();
|
||||||
|
if(not db.recipe_exists(recipe_id)) {
|
||||||
|
std::cerr << "Recipe with ID " << recipe_id << " does not exist." << std::endl;
|
||||||
|
db.close();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &i : tag_list) {
|
||||||
|
int tag_id;
|
||||||
|
trim(i);
|
||||||
|
|
||||||
|
if(not db.tag_exists(i)) {
|
||||||
|
std::cerr << "Could not find tag '" << i << "'. Skipping!" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag_id = db.get_tag_id(i);
|
||||||
|
db.disconn_recipe_tag(recipe_id, tag_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
@ -21,3 +21,7 @@ int cmd_add(void);
|
|||||||
int cmd_list(int argc, char *argv[]);
|
int cmd_list(int argc, char *argv[]);
|
||||||
int cmd_delete(int argc, char *argv[]);
|
int cmd_delete(int argc, char *argv[]);
|
||||||
int cmd_info(const int id);
|
int cmd_info(const int id);
|
||||||
|
int cmd_add_ingr(const int recipe_id, const char *ingredients);
|
||||||
|
int cmd_rm_ingr(const int recipe_id, const char *ingredients);
|
||||||
|
int cmd_add_tag(const int recipe_id, const char *tags);
|
||||||
|
int cmd_rm_tag(const int recipe_id, const char *tags);
|
||||||
|
36
src/db.cpp
36
src/db.cpp
@ -42,7 +42,7 @@ void db::open(void) {
|
|||||||
db_path += "/recipes.db";
|
db_path += "/recipes.db";
|
||||||
|
|
||||||
if(not std::filesystem::exists(db_path)) {
|
if(not std::filesystem::exists(db_path)) {
|
||||||
std::cout << "Creating database: " << db_path << std::endl;
|
std::cout << "Creating database in " << db_path << std::endl;
|
||||||
new_db = true;
|
new_db = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ int db::add_recipe(const std::string &name, const std::string &description) {
|
|||||||
if(not sqlite_db)
|
if(not sqlite_db)
|
||||||
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
if(sqlite3_exec(sqlite_db, std::format("INSERT INTO recipes(name,description) VALUES('{}','{}');", name, description).c_str(),
|
if(sqlite3_exec(sqlite_db, std::format("INSERT OR IGNORE INTO recipes(name,description) VALUES('{}','{}');", name, description).c_str(),
|
||||||
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
||||||
throw std::runtime_error("Failed to insert new recipe into database.");
|
throw std::runtime_error("Failed to insert new recipe into database.");
|
||||||
}
|
}
|
||||||
@ -251,7 +251,7 @@ int db::add_ingredient(const std::string &name) {
|
|||||||
if(not sqlite_db)
|
if(not sqlite_db)
|
||||||
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
if(sqlite3_exec(sqlite_db, std::format("INSERT INTO ingredients(name) VALUES(lower('{}'));", name).c_str(),
|
if(sqlite3_exec(sqlite_db, std::format("INSERT OR IGNORE INTO ingredients(name) VALUES(lower('{}'));", name).c_str(),
|
||||||
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
||||||
throw std::runtime_error(std::format("Failed to instert ingredient '{}'.", name));
|
throw std::runtime_error(std::format("Failed to instert ingredient '{}'.", name));
|
||||||
}
|
}
|
||||||
@ -280,7 +280,7 @@ int db::add_tag(const std::string &name) {
|
|||||||
if(not sqlite_db)
|
if(not sqlite_db)
|
||||||
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
if(sqlite3_exec(sqlite_db, std::format("INSERT INTO tags(name) VALUES('{}');", name).c_str(),
|
if(sqlite3_exec(sqlite_db, std::format("INSERT OR IGNORE INTO tags(name) VALUES('{}');", name).c_str(),
|
||||||
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
||||||
throw std::runtime_error(std::format("Failed to insert tag '{}'", name));
|
throw std::runtime_error(std::format("Failed to insert tag '{}'", name));
|
||||||
}
|
}
|
||||||
@ -305,24 +305,44 @@ std::vector<std::string> db::get_recipe_tags(const int id) {
|
|||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void db::conn_recipe_ingredient(int recipe_id, int ingredient_id) {
|
void db::conn_recipe_ingredient(const int recipe_id, const int ingredient_id) {
|
||||||
if(not sqlite_db)
|
if(not sqlite_db)
|
||||||
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
if(sqlite3_exec(sqlite_db, std::format("INSERT INTO recipe_ingredient(recipe_id, ingredient_id) VALUES({},{});", recipe_id, ingredient_id).c_str(),
|
if(sqlite3_exec(sqlite_db, std::format("INSERT OR IGNORE INTO recipe_ingredient(recipe_id, ingredient_id) VALUES({},{});", recipe_id, ingredient_id).c_str(),
|
||||||
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
||||||
throw std::runtime_error(std::format("Failed to connect recipe with ID {} to ingredient with ID {}",
|
throw std::runtime_error(std::format("Failed to connect recipe with ID {} to ingredient with ID {}",
|
||||||
recipe_id, ingredient_id));
|
recipe_id, ingredient_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void db::conn_recipe_tag(int recipe_id, int tag_id) {
|
void db::disconn_recipe_ingredient(const int recipe_id, const int ingredient_id) {
|
||||||
if(not sqlite_db)
|
if(not sqlite_db)
|
||||||
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
if(sqlite3_exec(sqlite_db, std::format("INSERT INTO recipe_tag(recipe_id, tag_id) VALUES({},{});", recipe_id, tag_id).c_str(),
|
if(sqlite3_exec(sqlite_db, std::format("DELETE FROM recipe_ingredient WHERE recipe_id={} AND ingredient_id={};", recipe_id, ingredient_id).c_str(),
|
||||||
|
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
||||||
|
throw std::runtime_error(std::format("Failed to disconnect recipe with ID {} from ingredient with ID {}.", recipe_id, ingredient_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void db::conn_recipe_tag(const int recipe_id, const int tag_id) {
|
||||||
|
if(not sqlite_db)
|
||||||
|
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
|
if(sqlite3_exec(sqlite_db, std::format("INSERT OR IGNORE INTO recipe_tag(recipe_id, tag_id) VALUES({},{});", recipe_id, tag_id).c_str(),
|
||||||
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
||||||
throw std::runtime_error(std::format("Failed to connect recipe with ID {} to tag with ID {}",
|
throw std::runtime_error(std::format("Failed to connect recipe with ID {} to tag with ID {}",
|
||||||
recipe_id, tag_id));
|
recipe_id, tag_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void db::disconn_recipe_tag(const int recipe_id, const int tag_id) {
|
||||||
|
if(not sqlite_db)
|
||||||
|
throw std::runtime_error(std::format("{}: Database not open! Please contact a developer.", __PRETTY_FUNCTION__));
|
||||||
|
|
||||||
|
if(sqlite3_exec(sqlite_db, std::format("DELETE FROM recipe_tag WHERE recipe_id={} AND tag_id={};", recipe_id, tag_id).c_str(),
|
||||||
|
nullptr, nullptr, nullptr) not_eq SQLITE_OK) {
|
||||||
|
throw std::runtime_error(std::format("Failed to disconnect recipe with ID {} from tag with ID {}.", recipe_id, tag_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -94,6 +94,8 @@ public:
|
|||||||
return (get_tag_id(name) > 0);
|
return (get_tag_id(name) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void conn_recipe_ingredient(int recipe_id, int ingredient_id);
|
void conn_recipe_ingredient(const int recipe_id, const int ingredient_id);
|
||||||
void conn_recipe_tag(int recipe_id, int tag_id);
|
void disconn_recipe_ingredient(const int recipe_id, const int ingredient_id);
|
||||||
|
void conn_recipe_tag(const int recipe_id, const int tag_id);
|
||||||
|
void disconn_recipe_tag(const int recipe_id, const int tag_id);
|
||||||
};
|
};
|
||||||
|
18
src/main.cpp
18
src/main.cpp
@ -41,15 +41,27 @@ int main(int argc, char *argv[]) {
|
|||||||
case CMD_ADD:
|
case CMD_ADD:
|
||||||
ret = cmd_add();
|
ret = cmd_add();
|
||||||
break;
|
break;
|
||||||
case CMD_LIST:
|
|
||||||
ret = cmd_list(argc - 1, argv + 1);
|
|
||||||
break;
|
|
||||||
case CMD_DEL:
|
case CMD_DEL:
|
||||||
ret = cmd_delete(argc - 2, argv + 2);
|
ret = cmd_delete(argc - 2, argv + 2);
|
||||||
break;
|
break;
|
||||||
|
case CMD_LIST:
|
||||||
|
ret = cmd_list(argc - 1, argv + 1);
|
||||||
|
break;
|
||||||
case CMD_INFO:
|
case CMD_INFO:
|
||||||
ret = cmd_info(std::stoi(argv[2]));
|
ret = cmd_info(std::stoi(argv[2]));
|
||||||
break;
|
break;
|
||||||
|
case CMD_ADD_INGR:
|
||||||
|
ret = cmd_add_ingr(std::stoi(argv[2]), argv[3]);
|
||||||
|
break;
|
||||||
|
case CMD_RM_INGR:
|
||||||
|
ret = cmd_rm_ingr(std::stoi(argv[2]), argv[3]);
|
||||||
|
break;
|
||||||
|
case CMD_ADD_TAG:
|
||||||
|
ret = cmd_add_tag(std::stoi(argv[2]), argv[3]);
|
||||||
|
break;
|
||||||
|
case CMD_RM_TAG:
|
||||||
|
ret = cmd_rm_tag(std::stoi(argv[2]), argv[3]);
|
||||||
|
break;
|
||||||
case CMD_HELP:
|
case CMD_HELP:
|
||||||
print_help();
|
print_help();
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user