diff --git a/.gitignore b/.gitignore index 6367d07..2ee2b4d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,4 @@ gradle-app.setting __MACOSX .DS_Store .vscode -krusty.sqlite3 - -*.sqlite3 -*.db +krusty.sqlite3 \ No newline at end of file diff --git a/app/Migrations/0010-tables.sql b/app/Migrations/0010-tables.sql new file mode 100644 index 0000000..23f64bd --- /dev/null +++ b/app/Migrations/0010-tables.sql @@ -0,0 +1,88 @@ +CREATE TABLE IF NOT EXISTS Customers ( + CustomerID int PRIMARY KEY, + Name varchar(100), + Address varchar(255) +); + +CREATE TABLE IF NOT EXISTS Products ( + ProductID int PRIMARY KEY, + Name varchar(100) +); + +CREATE TABLE IF NOT EXISTS Recipes ( + RecipeName varchat(100), + RecipeYear Year, + ingrediences int, + ProductID int, + PRIMARY KEY (RecipeName, RecipeYear), + FOREIGN KEY (ingrediences) REFERENCES ingredience(IngredienceID), + FOREIGN KEY (ProductID) REFERENCES Products(ProductID) +); + +CREATE TABLE IF NOT EXISTS ingredience ( + IngredienceID int PRIMARY KEY, + RawMaterialName varchar(100), + amount int, + unit varchar(50), + FOREIGN KEY (RawMaterialName) REFERENCES RawMaterials(RawMaterialName) +); + +CREATE TABLE IF NOT EXISTS RawMaterials ( + RawMaterialName varchar(100) PRIMARY KEY, + Quantity int, + LastDeliveryDateTime datetime +); + +CREATE TABLE IF NOT EXISTS PalletsProduced ( + PalletID int PRIMARY KEY, + ProductID int, + ProductionDateTime datetime, + FOREIGN KEY (ProductID) REFERENCES Products (ProductID) +); + +CREATE TABLE IF NOT EXISTS PalletsDelivered ( + DeliveredID int PRIMARY KEY, + PalletID int, + DeliveryDateTime datetime, + FOREIGN KEY (PalletID) REFERENCES PalletsProduced (PalletID), + FOREIGN KEY (DeliveredID) REFERENCES Truck (Pallet) +); + +CREATE TABLE IF NOT EXISTS Truck ( + truckId int PRIMARY KEY, + capacity int, + Pallet int +); + +CREATE TABLE IF NOT EXISTS loadingBill ( + LoadingbillID int PRIMARY KEY, + adress varchar(100), + customer varchar(100), + truckID int, + FOREIGN KEY (truckID) REFERENCES Truck (truckId) +); + +CREATE TABLE IF NOT EXISTS Orders ( + OrderID int PRIMARY KEY, + CustomerID int, + ProductID int, + Quantity int, + OrderDateTime datetime, + FOREIGN KEY (CustomerID) REFERENCES Customers (CustomerID), + FOREIGN KEY (ProductID) REFERENCES Products (ProductID) +); + +CREATE TABLE IF NOT EXISTS BlockedProducts ( + BlockedProductID int PRIMARY KEY, + ProductID int, + BlockedDateTime datetime, + FOREIGN KEY (ProductID) REFERENCES Products (ProductID) +); + +CREATE TABLE IF NOT EXISTS PalletTraceability ( + TraceID int PRIMARY KEY, + location varchar(100), + locationdate datetime, + PalletID int, + FOREIGN KEY (PalletID) REFERENCES PalletsProduced (PalletID) +); diff --git a/app/Migrations/0020-data.sql b/app/Migrations/0020-data.sql new file mode 100644 index 0000000..2cac31f --- /dev/null +++ b/app/Migrations/0020-data.sql @@ -0,0 +1,4 @@ +-- Inserts here +INSERT INTO Customers (CustomerID, Name, Address) VALUES + (1, 'John Doe', '123 Main St'), + (2, 'Jane Smith', '456 Elm St'); \ No newline at end of file diff --git a/app/Migrations/create-schema.sql b/app/Migrations/create-schema.sql deleted file mode 100644 index 483694f..0000000 --- a/app/Migrations/create-schema.sql +++ /dev/null @@ -1,83 +0,0 @@ --------------------------------------------- --- Recipe/Cookie related tables --------------------------------------------- - --- Our known customers, may need more fields -CREATE TABLE IF NOT EXISTS customers ( - customer_id int PRIMARY KEY, - customer_name varchar(100), - customer_address varchar(255) -); - --- Orders from customers. --- Keep in mind that the delivery_date may be NULL -CREATE TABLE IF NOT EXISTS orders ( - order_id int PRIMARY KEY, - customer_id int, - order_date date DEFAULT NOW, - delivery_date date, -- Set when the order hits the truck - FOREIGN KEY (customer_id) REFERENCES customers(customer_id) -); - --------------------------------------------- --- Recipe/Cookie related tables --------------------------------------------- - --- Recipes for all the cookies (essentially a list of cookies) -CREATE TABLE IF NOT EXISTS recipes ( - recipe_id int PRIMARY KEY, - recipe_name varchar(100) -- Cookie name -); - --- "The company has a raw materials warehouse in which --- all ingredients used in their production are stored." - --- Describes ingredients and stock. --- Each ingredient has 'amount' of 'unit' in stock -CREATE TABLE IF NOT EXISTS ingredients ( - ingredient_id int PRIMARY KEY, - ingredient_name varchar(100), - amount int, - unit varchar(50) -); - --- Describes what ingredients goes into what recipe --- Each recipe requires 'amount' of 'ingredient' -CREATE TABLE IF NOT EXISTS recipe_contents ( - recipe_id int, - ingredient_id int, - amount int, - PRIMARY KEY (recipe_id, ingredient_id) -); - --------------------------------------------- --- Pallet related tables --------------------------------------------- - --- Pallets are used to store cookies for delivery -CREATE TABLE IF NOT EXISTS pallets ( - pallet_id int PRIMARY KEY, - recipe_id int, - order_id int, - FOREIGN KEY (recipe_id) REFERENCES recipes(recipe_id), - FOREIGN KEY (order_id) REFERENCES Orders(order_id) -); - --- What does the pallet contain? -CREATE TABLE IF NOT EXISTS pallet_contents ( - pallet_id int, - ingredient_id int, - amount int, - PRIMARY KEY (pallet_id, ingredient_id), - FOREIGN KEY (pallet_id) REFERENCES pallets(pallet_id), - FOREIGN KEY (ingredient_id) REFERENCES ingredients(ingredient_id) -); - --- Has an order been delivered? --- When the truck is loaded, a delivery is considered done -CREATE TABLE IF NOT EXISTS delivery_bill ( - delivery_id int PRIMARY KEY, - order_id int, - delivery_date date DEFAULT NOW, - FOREIGN KEY (order_id) REFERENCES Orders(order_id) -); \ No newline at end of file diff --git a/app/Migrations/initial-data.sql b/app/Migrations/initial-data.sql deleted file mode 100644 index 4dbbd05..0000000 --- a/app/Migrations/initial-data.sql +++ /dev/null @@ -1,22 +0,0 @@ --- Inserts here -INSERT OR IGNORE INTO - customers (customer_id, customer_name, customer_address) -VALUES - (1, 'Bjudkakor AB', 'Ystad'), - (2, 'Finkakor AB', 'Helsingborg'), - (3, 'Gästkakor AB', 'Hässleholm'), - (4, 'Kaffebröd AB', 'Landskrona'), - (5, 'Kalaskakor AB', 'Trelleborg'), - (6, 'Partykakor AB', 'Kristianstad'), - (7, 'Skånekakor AB', 'Perstorp'), - (8, 'Småbröd AB', 'Malmö'); - -INSERT INTO - recipes (recipe_name) -VALUES - ('Nut ring'), - ('Nut cookie'), - ('Amneris'), - ('Tango'), - ('Almond delight'), - ('Berliner'); \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 807df65..c8a22dc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,8 +18,8 @@ repositories { dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") - testImplementation("org.skyscreamer:jsonassert:1.5.0") // For JSON assertions in tests. - testImplementation("com.mashape.unirest:unirest-java:1.4.9") // For HTTP requests in tests. + // testImplementation("org.skyscreamer:jsonassert:1.5.0") // For JSON assertions in tests. + // testImplementation("com.mashape.unirest:unirest-java:1.4.9") // For HTTP requests in tests. testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.2") // implementation("com.google.guava:guava:33.1.0-jre") // Currently not used. diff --git a/app/src/main/java/krusty/Database.java b/app/src/main/java/krusty/Database.java index 26ef811..e673436 100644 --- a/app/src/main/java/krusty/Database.java +++ b/app/src/main/java/krusty/Database.java @@ -8,29 +8,21 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; +import java.io.BufferedReader; // Likely dependencies for general operations import java.io.IOException; -import java.sql.ResultSet; -import java.util.StringJoiner; -import java.util.stream.Collectors; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.stream.Stream; +import java.io.FileReader; 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"; + private static final String jdbcString = "jdbc:sqlite::memory:"; private Connection conn = null; public String getCustomers(Request req, Response res) { - String result = selectQuery("customers", "customers", "customer_name", "customer_address"); - result = result.replaceAll("customer_name", "name"); - result = result.replaceAll("customer_address", "address"); - return result; + return "{}"; } public String getRawMaterials(Request req, Response res) { @@ -38,8 +30,7 @@ public class Database { } public String getCookies(Request req, Response res) { - String result = selectQuery("recipes", "cookies", "recipe_name"); - return result; + return "{\"cookies\":[]}"; } public String getRecipes(Request req, Response res) { @@ -69,65 +60,31 @@ public class Database { } } - /** - * Selects columns from a table and returns the result as a JSON string. - * Does _absolutely no_ query sanitization, so be careful with user input. - */ - private String selectQuery(String table, String jsonName, String... columns) { - String jsonResult = "{}"; // Valid json to return if fail - - try { - Statement stmt = this.conn.createStatement(); - StringBuilder query = new StringBuilder("SELECT "); - - StringJoiner args = new StringJoiner(", "); - for (String column : columns) { - args.add(column); - } - - query.append(args.toString()); - query.append(" FROM " + table + ";"); - - /* Sanitization is for cowards */ - - ResultSet result = stmt.executeQuery(query.toString()); - jsonResult = Jsonizer.toJson(result, jsonName); - } catch (SQLException e) { - System.out.printf("Error executing query: \n%s", e); - } - - return jsonResult; - } - // The script location is relative to the gradle // build script ("build.gradle.kts", in this case). /** Reads an sql script into the database */ public void migrateScript(String filename) throws IOException, SQLException { - try (Stream lines = Files.lines(Paths.get(filename))) { + try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { + StringBuilder scriptBuilder = new StringBuilder(); + String line; - // Combine into one big string, with all comments and empty lines removed. - String[] statements = lines.filter(line -> !line.startsWith("--") && !line.isBlank()) - .map(line -> line.replaceAll("--.*", "").replaceAll("\\s+", " ").trim()) - .collect(Collectors.joining("\n")).split(";"); + // Read the script file line by line + while ((line = reader.readLine()) != null) { + scriptBuilder.append(line).append("\n"); + } + String script = scriptBuilder.toString().trim(); - for (String query : statements) { - try (Statement statement = conn.createStatement()) { - statement.execute(query); - statement.close(); - } catch (SQLException e) { - System.err.println("Error executing script: " + e.getMessage()); - throw e; - } + // Execute the script + try (Statement statement = conn.createStatement()) { + statement.execute(script); } System.out.println(String.format("Executed script %s", filename)); - } catch (IOException e) { System.err.println("Error reading script file: " + e.getMessage()); throw e; } catch (SQLException e) { - String prepend = String.format("Error executing script: %s", filename); - System.err.println(prepend + e.getMessage()); + System.err.println("Error executing script: " + e.getMessage()); throw e; } } -} \ No newline at end of file +} diff --git a/app/src/main/java/krusty/DefaultRecipes.java b/app/src/main/java/krusty/DefaultRecipes.java deleted file mode 100644 index 87d8324..0000000 --- a/app/src/main/java/krusty/DefaultRecipes.java +++ /dev/null @@ -1,57 +0,0 @@ -package krusty; - -import java.util.Arrays; -import java.util.List; - -public class DefaultRecipes { - public static List recipes = Arrays.asList( - new Recipe("Nut ring", - new Ingredient[] { - new Ingredient("Flour", 450, "g"), - new Ingredient("Butter", 450, "g"), - new Ingredient("Icing sugar", 190, "g"), - new Ingredient("Roasted, chopped nuts", 225, "g") - }), - new Recipe("Nut cookie", - new Ingredient[] { - new Ingredient("Fine-ground nuts", 750, "g"), - new Ingredient("Ground, roasted nuts", 625, "g"), - new Ingredient("Bread crumbs", 125, "g"), - new Ingredient("Sugar", 375, "g"), - new Ingredient("Egg Whites", 350, "ml"), - new Ingredient("Chocolate", 50, "g") - }), - new Recipe("Amneris", - new Ingredient[] { - new Ingredient("Marzipan", 750, "g"), - new Ingredient("Butter", 250, "g"), - new Ingredient("Eggs", 250, "g"), - new Ingredient("Potato starch", 25, "g"), - new Ingredient("Wheat flour", 25, "g") - }), - new Recipe("Tango", - new Ingredient[] { - new Ingredient("Butter", 200, "g"), - new Ingredient("Sugar", 250, "g"), - new Ingredient("Flour", 300, "g"), - new Ingredient("Sodium bicarbonate", 4, "g"), - new Ingredient("Vanilla", 2, "g") - }), - new Recipe("Almond delight", - new Ingredient[] { - new Ingredient("Butter", 400, "g"), - new Ingredient("Sugar", 270, "g"), - new Ingredient("Chopped almonds", 279, "g"), - new Ingredient("Flour", 400, "g"), - new Ingredient("Cinnamon", 10, "g") - }), - new Recipe("Berliner", - new Ingredient[] { - new Ingredient("Flour", 350, "g"), - new Ingredient("Butter", 250, "g"), - new Ingredient("Icing sugar", 100, "g"), - new Ingredient("Eggs", 50, "g"), - new Ingredient("Vanilla sugar", 5, "g"), - new Ingredient("Chocolate", 50, "g") - })); -} \ No newline at end of file diff --git a/app/src/main/java/krusty/Ingredient.java b/app/src/main/java/krusty/Ingredient.java deleted file mode 100644 index 04be1ca..0000000 --- a/app/src/main/java/krusty/Ingredient.java +++ /dev/null @@ -1,16 +0,0 @@ -package krusty; - -public class Ingredient { - public String name, unit; - public int amount; - - public Ingredient(String name, int amount, String unit) { - this.name = name; - this.amount = amount; - this.unit = unit; - } - - public String toString() { - return String.format("%s: %d %s", name, amount, unit); - } -} \ No newline at end of file diff --git a/app/src/main/java/krusty/Recipe.java b/app/src/main/java/krusty/Recipe.java deleted file mode 100644 index 864e39a..0000000 --- a/app/src/main/java/krusty/Recipe.java +++ /dev/null @@ -1,15 +0,0 @@ -package krusty; - -public class Recipe { - public String name; - public Ingredient ingredients[]; - - public Recipe(String name, Ingredient[] ingredients) { - this.name = name; - this.ingredients = ingredients; - } - - public String toString() { - return name; - } -} \ No newline at end of file diff --git a/app/src/main/java/krusty/ServerMain.java b/app/src/main/java/krusty/ServerMain.java index 8e7c2ce..d753727 100644 --- a/app/src/main/java/krusty/ServerMain.java +++ b/app/src/main/java/krusty/ServerMain.java @@ -20,8 +20,8 @@ public class ServerMain { // Here, we can migrate an arbitrary number of SQL scripts. try { - db.migrateScript("Migrations/create-schema.sql"); - db.migrateScript("Migrations/initial-data.sql"); + db.migrateScript("Migrations/0010-tables.sql"); + db.migrateScript("Migrations/0020-data.sql"); } catch (Exception e) { throw new IOError(e); } diff --git a/makefile b/makefile index dec224d..5c904f3 100644 --- a/makefile +++ b/makefile @@ -10,11 +10,4 @@ clean: test: ./gradlew test -dbdump: - sqlite3 app/krusty.db .dump - -migrate: - sqlite3 app/krusty.db < app/Migrations/create-schema.sql - sqlite3 app/krusty.db < app/Migrations/initial-data.sql - -.PHONY: run clean test build +.PHONY: run clean test build \ No newline at end of file