Giter Club home page Giter Club logo

suchapalaver / gust Goto Github PK

View Code? Open in Web Editor NEW
6.0 1.0 0.0 601 KB

Built in Rust and leveraging Docker, JSON, and SQLite (with future integration of a GraphQL API), 'gust' simplifies the process of preserving your recipes and creating comprehensive grocery shopping lists.

Home Page: https://github.com/suchapalaver/gust

License: MIT License

Rust 98.49% Dockerfile 0.23% Makefile 1.28%
rust rust-lang serde serde-json clap beginner-project beginner-friendly error-handling deserialization command-line-app

gust's People

Contributors

suchapalaver avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

gust's Issues

Support NYT recipes

gust currently only supports requests for recipes from the BBC Food website.

Better organization

For example Groceries contains write_to_file, read_from_file, and get_sections. These aren't really specific to the impl for a given instance of Groceries. It feels like maybe these should be made into a module rather than an impl block.

Sort out command line

Right now clap isn't being used particularly correctly. Let's aim for arguments like the following for a start:
cargo run -- recipe new "tofu chicken rice" --ingredients tofu rice chicken garlic
And have the same minus the --ingredients flag run a default that asks the user for ingredients input

Support updating section for items

Currently we have a rigid system using:

pub const SECTIONS: [&str; 5] = ["fresh", "pantry", "protein", "dairy", "freezer"];

This should be flexible according the user.

Make `...or_insert` methods make more sense

Below is just one example where we're inefficiently inserting using on_conflict_do_nothing to ensure that an item is present in our store, a good example of the kind of path of least resistance that doesn’t lead to a good place.

//! crates/persistence/src/sqlite/mod.rs

fn get_or_insert_item(
    &mut self,
    connection: &mut SqliteConnection,
    name: &str,
) -> Result<i32, StoreError> {
    diesel::insert_into(schema::items::table)
        .values(NewItem { name })
        .on_conflict_do_nothing()
        .execute(connection)?;

    let item_query = schema::items::table.filter(schema::items::dsl::name.eq(name));

    Ok(item_query
        .select(schema::items::dsl::id)
        .first(connection)?)
}

A lot of things are just strings. These could made type safe by creating types for these things and using shrinkwraprs to retain all the expected methods from string.

For example you have:

struct GroceriesSection {
    section: String,
    items: Vec<String>,
}
struct Recipe {
    recipe: String,
    ingredients: Vec<String>,
}
struct ShoppingList {
    recipes_msg: String,
    recipes: Vec<String>,
    checklist_msg: String,
    checklist: Vec<String>,
    list_msg: String,
    list: Vec<String>,
}

Here the types do not make clear which items are used in which places. For example GroceriesSection::String is totally unrelated to the items in Recipe::ingredients. However GroceriesSection::items is the same. So rather than all of these being just String you could have types like:

#[derive(Shrinkwrap)]
struct RecipeName(String);
#[derive(Shrinkwrap)]
struct Ingredient{ name: String }
``
etc. (using shrinkwraprs 3)
This would make things like `ShoppingList` much easier to understand by looking at the struct.

Improved error handling

Errors aren’t specific enough right now. Good example if there’s some problem with the JSON files.

Make fetching and adding recipes idempotent

Adding the same recipe, for example by running make fetch url=https://www.bbc.co.uk/food/recipes/vegetable_noodle_pancake_22079 twice will result in something like this:

2023-12-28T18:15:32.603913Z ERROR api: API dispatch, error: StoreError(DBQuery(DatabaseError(UniqueViolation, "UNIQUE constraint failed: items_recipes.item_id, items_recipes.recipe_id")))
    at crates/api/src/lib.rs:104

a next step if you're into it--subcommands using clap

I'm not a huge fan of running through asking what operation you want to perform. Maybe you could look into using subcommands with the clap crate, so if you want to add a recipe to the library you don't have to enter n a bunch of times.

You could also make a help subcommand that prints some info and maybe with no subcommand you can run the same process you have.

Once you have them broken into subcommands you'll see that running one after the other looks much cleaner too.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.