diff --git a/app/Migrations/create-schema.sql b/app/Migrations/create-schema.sql index 4ff9482..3517751 100644 --- a/app/Migrations/create-schema.sql +++ b/app/Migrations/create-schema.sql @@ -52,14 +52,13 @@ CREATE TABLE IF NOT EXISTS raw_materials_deliveries ( -------------------------------------------- -- Pallets are used to store cookies for delivery --- Order related columns are unused for now. CREATE TABLE IF NOT EXISTS pallets ( pallet_id INT PRIMARY KEY, cookie_id INT NOT NULL, - -- order_id INT NOT NULL, + order_id INT NOT NULL, status VARCHAR(50) NOT NULL CHECK (status IN ('freezer', 'delivered', 'blocked')), production_date DATE NOT NULL, delivery_date DATE DEFAULT NULL, FOREIGN KEY (cookie_id) REFERENCES cookies(cookie_id) - -- FOREIGN KEY (order_id) REFERENCES orders(order_id) + FOREIGN KEY (order_id) REFERENCES orders(order_id) ); diff --git a/app/src/main/java/krusty/Database.java b/app/src/main/java/krusty/Database.java index 7a8fed9..96ea689 100644 --- a/app/src/main/java/krusty/Database.java +++ b/app/src/main/java/krusty/Database.java @@ -6,15 +6,11 @@ import spark.Response; // Likely dependencies for db operations import java.sql.Connection; import java.sql.DriverManager; -import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; -import java.text.SimpleDateFormat; // Likely dependencies for general operations import java.io.IOException; import java.sql.ResultSet; -import java.util.Date; -import java.util.Optional; import java.util.StringJoiner; import java.util.stream.Collectors; import java.nio.file.Files; @@ -22,16 +18,12 @@ import java.nio.file.Paths; import java.util.stream.Stream; public class Database { - // Here, we use an in-memory database. This string could be changed to // "jdbc:sqlite:.sqlite3" to use a file-based database instead. // Nore that ":memory:" is an **SQLite specific** magic string that tells the // underlying SQLite engine to store the database in memory. private static final String jdbcString = "jdbc:sqlite::memory:"; // private static final String jdbcString = "jdbc:sqlite:krusty.db"; - - // Hold a single connection to the database. Note that this is - // not a pool, so this is not thread-safe nor efficient. private Connection conn = null; public String getCustomers(Request req, Response res) { @@ -60,115 +52,9 @@ public class Database { } public String getPallets(Request req, Response res) { - // These queries look like: - // http://localhost:8888/api/v1/pallets?cookie=Nut+cookie&from=2024-05-23&to=2024-05-30&blocked=yes - // They may contain any combination of the parameters, or none at all. - - Optional r = Optional.empty(); // Holds the ecipe if we have a cookie - Optional blocked = Optional.empty(); // Holds the blocked status - Optional from = Optional.empty(); // Holds the from date - Optional to = Optional.empty(); // Holds the to date - - // First we need the cookie parameter - String cookie = req.queryParams("cookie"); - - // And the blocked parameter - String blocked_str = req.queryParams("blocked"); - - // Then we need the date parameters - String from_str = req.queryParams("from"); - String to_str = req.queryParams("to"); - - // Date from = null; - // Date to = null; - - // Fancy functional one-liner to get the recipe if the cookie is present - if (cookie != null) { - r = Optional.ofNullable(DefaultRecipes.recipes.stream() - .filter(recipe -> recipe.name.equals(cookie)) - .findFirst().orElse(null)); - } - - if (blocked_str != null) { - blocked = switch (blocked_str) { - case "yes" -> Optional.of(true); - case "no" -> Optional.of(false); - default -> Optional.empty(); - }; - } - - // Both of these must be present - if (from_str != null && to_str != null) { - try { - // Parse both in the format (2024-05-23), also called ISO 8601 - from = Optional.of(new SimpleDateFormat("yyyy-MM-dd").parse(from_str)); - to = Optional.of(new SimpleDateFormat("yyyy-MM-dd").parse(to_str)); - } catch (Exception e) { - // Reset the dates to empty - from = Optional.empty(); - to = Optional.empty(); - // We have a bad date, maybe log this somewhere - } - - // Check so that the dates are in the correct order - if (from.isPresent() && to.isPresent() && from.get().after(to.get())) { - // We have a bad interval, perhaps set dates to empty agian? - // TODO: This obviously need louder error handling - from = Optional.empty(); - to = Optional.empty(); - } - } - - // This type of code is unreadable, error prone and hard to maintain. - // The fact that im responsible for this code makes my soul hurt. - // This part almost made me write a simple query factory to handle this. - // - // SqlBuilder exists to 'take the pain out of generating SQL queries', - // but it's not in the standard library. - // - // Helmets, seatbelts and safety goggles on; we need to execute a query. - try { - Statement stmt = conn.createStatement(); - StringBuilder query = new StringBuilder( - "SELECT * FROM pallets JOIN cookies ON pallets.cookie_id = cookies.cookie_id"); - - // r is validated here - if (r.isPresent()) { - query.append(" WHERE cookie_name = '" + r.get().name + "'"); - } - - if (from != null && to != null) { - if (r.isPresent()) { - query.append(" AND "); - } else { - query.append(" WHERE "); - } - - query.append("production_date BETWEEN '" + from_str + "' AND '" + to_str + "'"); - } - - if (blocked.isPresent()) { - // WARNING THIS IS NOT CORRECT WARNING - if (r.isPresent() || from != null) { - query.append(" AND "); - } - - // TODO: WARNING This logic is flawed. WARNING - // Remember, status can be 'freezer', 'delivered' or 'blocked' - query.append("status = " + (blocked.get() ? "'blocked'" : "'freezer'")); - } - - query.append(";"); - ResultSet result = stmt.executeQuery(query.toString()); - String jsonResult = Jsonizer.toJson(result, "pallets"); - return jsonResult; - } catch (SQLException e) { - System.out.printf("Error executing query: \n%s", e); - } - - // Statue 500, to give the client a - // chance to figure out that something went wrong - res.status(500); + // 1. Get query param -> validate cookie type if not null + // 2. Figure out if we should return all pallets or just one type + // 3. Return pallets as {cookie, blocked} return "{\"pallets\":[]}"; } @@ -180,67 +66,6 @@ public class Database { } public String createPallet(Request req, Response res) { - // This on only has one query param and looks like: - // http://localhost:8888/api/v1/pallets?cookie=Amneris - - Optional r = Optional.empty(); - String cookie = req.queryParams("cookie"); - - if (cookie != null) { - r = Optional.ofNullable(DefaultRecipes.recipes.stream() - .filter(recipe -> recipe.name.equals(cookie)) - .findFirst().orElse(null)); - } - - if (r.isEmpty()) { - // Return 404 - res.status(404); - return "{}"; - } - - try (PreparedStatement getRawMaterials = conn.prepareStatement("SELECT * FROM raw_materials WHERE ingredient_name = ?"); - PreparedStatement decrementRawMaterials = conn.prepareStatement("UPDATE raw_materials SET ingredient_quantity = ingredient_quantity - ? WHERE ingredient_name = ?"); - PreparedStatement insertPallet = conn.prepareStatement("INSERT INTO pallets (cookie_id, production_date, status) VALUES (?, ?, ?)")) { - // Start transaction - conn.setAutoCommit(false); - - for(Ingredient i : r.get().ingredients) { - getRawMaterials.setString(1, i.name); - ResultSet result = getRawMaterials.executeQuery(); - if (!result.next()) { - // Rollback transaction - conn.rollback(); - // Return 500 - res.status(500); - return "{}"; - } - - // Check if we have enough raw materials - if (result.getInt("ingredient_quantity") < i.amount) { - // Rollback transaction - conn.rollback(); - // Return 500 - res.status(500); - return "{}"; - } - - decrementRawMaterials.setInt(1, i.amount * 54); // 5400 / 100 - decrementRawMaterials.setString(2, i.name); - decrementRawMaterials.executeUpdate(); - } - - insertPallet.setInt(1, 1); - insertPallet.setString(2, new SimpleDateFormat("yyyy-MM-dd").format(new Date())); - insertPallet.setString(3, "freezer"); - - insertPallet.executeUpdate(); - conn.commit(); - } catch (SQLException e) { - System.out.printf("Error starting transaction: \n%s", e); - } - - // TODO: NOT DONE - // 1. Get query param // 2. Check if cookie exists (is in DefaultRecipes) // 3. Start transaction