Merge branch 'BackendOfIngredients' into 'main'
backend stuff for ingredients and nutritions See merge request cse1105/2025-2026/teams/csep-team-76!14
This commit is contained in:
commit
cc75e42e8e
8 changed files with 343 additions and 0 deletions
58
commons/src/main/java/commons/Ingredient.java
Normal file
58
commons/src/main/java/commons/Ingredient.java
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
package commons;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Ingredient {
|
||||||
|
|
||||||
|
//I don't like magic numbers
|
||||||
|
// online it says nutrition are this much kcal per gram
|
||||||
|
public static final double KCAL_PER_GRAM_PROTEIN = 4.0;
|
||||||
|
public static final double KCAL_PER_GRAM_CARBS = 4.0;
|
||||||
|
public static final double KCAL_PER_GRAM_FAT= 9.0;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
public long id;
|
||||||
|
|
||||||
|
@Column(name = "name", nullable = false, unique = true)
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
|
||||||
|
@Column(name = "protein", nullable = false)
|
||||||
|
public double proteinPer100g;
|
||||||
|
|
||||||
|
@Column(name = "fat", nullable = false)
|
||||||
|
public double fatPer100g;
|
||||||
|
|
||||||
|
@Column(name = "carbs", nullable = false)
|
||||||
|
public double carbsPer100g;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
protected Ingredient() {
|
||||||
|
// for object mapper says sebastian
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ingredient(String name,
|
||||||
|
double proteinPer100g,
|
||||||
|
double fatPer100g,
|
||||||
|
double carbsPer100g) {
|
||||||
|
this.name = name;
|
||||||
|
this.proteinPer100g = proteinPer100g;
|
||||||
|
this.fatPer100g = fatPer100g;
|
||||||
|
this.carbsPer100g = carbsPer100g;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double kcalPer100g() {
|
||||||
|
return proteinPer100g * KCAL_PER_GRAM_PROTEIN
|
||||||
|
+ carbsPer100g * KCAL_PER_GRAM_CARBS
|
||||||
|
+ fatPer100g * KCAL_PER_GRAM_FAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
77
commons/src/main/java/commons/RecipeIngredient.java
Normal file
77
commons/src/main/java/commons/RecipeIngredient.java
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
package commons;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class RecipeIngredient {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
public Long id;
|
||||||
|
|
||||||
|
// which recipe is used
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "recipe_id")
|
||||||
|
public Recipe recipe;
|
||||||
|
|
||||||
|
//which ingredient is used
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "ingredient_id")
|
||||||
|
public Ingredient ingredient;
|
||||||
|
|
||||||
|
public double amount;
|
||||||
|
|
||||||
|
// store the unit name in the database
|
||||||
|
public String unitName;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
protected RecipeIngredient() {
|
||||||
|
// for sebastian
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecipeIngredient(Recipe recipe, //which recipe
|
||||||
|
Ingredient ingredient, // which ingredient
|
||||||
|
double amount, // the amount
|
||||||
|
String unit) { //gram liter etc
|
||||||
|
//store it im tha field
|
||||||
|
this.recipe = recipe;
|
||||||
|
this.ingredient = ingredient;
|
||||||
|
this.amount = amount;
|
||||||
|
this.unitName = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert unitName to Unit object so java can read it
|
||||||
|
public Unit getUnit() {
|
||||||
|
return switch (unitName) {
|
||||||
|
case "GRAM" -> Unit.GRAM;
|
||||||
|
case "KILOGRAM" -> Unit.KILOGRAM;
|
||||||
|
case "MILLILITER" -> Unit.MILLILITER;
|
||||||
|
case "LITER" -> Unit.LITER;
|
||||||
|
case "TABLESPOON" -> Unit.TABLESPOON;
|
||||||
|
case "TEASPOON" -> Unit.TEASPOON;
|
||||||
|
case "CUP" -> Unit.CUP;
|
||||||
|
case "PIECE" -> Unit.PIECE;
|
||||||
|
|
||||||
|
case "PINCH" -> Unit.PINCH;
|
||||||
|
case "HANDFUL" -> Unit.HANDFUL;
|
||||||
|
case "TO_TASTE" -> Unit.TO_TASTE;
|
||||||
|
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public double amountInBaseUnit() {
|
||||||
|
Unit unit = getUnit();
|
||||||
|
if (unit == null || unit.isFormal() || unit.conversionFactor <= 0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return amount * unit.conversionFactor;
|
||||||
|
}
|
||||||
|
}
|
||||||
62
commons/src/main/java/commons/Unit.java
Normal file
62
commons/src/main/java/commons/Unit.java
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
package commons;
|
||||||
|
|
||||||
|
//what is a record class and why is it recommended
|
||||||
|
public final class Unit {
|
||||||
|
|
||||||
|
|
||||||
|
//stupid magic numbers
|
||||||
|
private static final double GRAMS = 1.0;
|
||||||
|
private static final double KILOGRAMS = 1000.0;
|
||||||
|
private static final double MILLILITERS = 1.0;
|
||||||
|
private static final double LITERS = 1000.0;
|
||||||
|
private static final double TABLESPOONS = 15.0;
|
||||||
|
private static final double TEASPOONS = 5.0;
|
||||||
|
private static final double CUPS = 240.0;
|
||||||
|
private static final double PIECES = 1.0;
|
||||||
|
|
||||||
|
private static final double NoMeaningfulValue = 0.0;
|
||||||
|
|
||||||
|
|
||||||
|
//formal units
|
||||||
|
//weight units
|
||||||
|
public static final Unit GRAM = new Unit("GRAM", true, GRAMS);
|
||||||
|
public static final Unit KILOGRAM = new Unit("KILOGRAM", true, KILOGRAMS );
|
||||||
|
|
||||||
|
//volume units
|
||||||
|
public static final Unit MILLILITER = new Unit("MILLILITER",true, MILLILITERS);
|
||||||
|
public static final Unit LITER = new Unit("LITER", true, LITERS);
|
||||||
|
public static final Unit TABLESPOON = new Unit("TABLESPOON",true, TABLESPOONS);
|
||||||
|
public static final Unit TEASPOON = new Unit("TEASPOON", true, TEASPOONS);
|
||||||
|
public static final Unit CUP = new Unit("CUP", true, CUPS);
|
||||||
|
|
||||||
|
//piece should be a formal unit to converse for portions like 3eggs can become 1,5 eggs this way
|
||||||
|
public static final Unit PIECE = new Unit("PIECE", true, PIECES);
|
||||||
|
|
||||||
|
//informal units
|
||||||
|
public static final Unit PINCH = new Unit("PINCH", false, NoMeaningfulValue);
|
||||||
|
public static final Unit HANDFUL = new Unit("HANDFUL", false, NoMeaningfulValue);
|
||||||
|
public static final Unit TO_TASTE = new Unit("TO_TASTE", false, NoMeaningfulValue);
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final boolean formal;
|
||||||
|
public final double conversionFactor;
|
||||||
|
|
||||||
|
private Unit(String name, boolean formal, double conversionFactor) {
|
||||||
|
this.name = name;
|
||||||
|
this.formal = formal;
|
||||||
|
this.conversionFactor = conversionFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFormal() {
|
||||||
|
return formal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInformal() {
|
||||||
|
return !formal;
|
||||||
|
} //for oskar
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
commons/src/test/java/commons/IngredientTest.java
Normal file
46
commons/src/test/java/commons/IngredientTest.java
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package commons;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class IngredientTest {
|
||||||
|
|
||||||
|
// === Meaningful constants ===
|
||||||
|
private static final double ZERO = 0.0;
|
||||||
|
private static final double HUNDRED = 100.0;
|
||||||
|
|
||||||
|
private static final double PROTEIN_10 = 10.0;
|
||||||
|
private static final double FAT_5 = 5.0;
|
||||||
|
private static final double CARBS_20 = 20.0;
|
||||||
|
|
||||||
|
private static final double EXPECTED_KCAL_165 = 165.0;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkConstructorIngredient() {
|
||||||
|
Ingredient sugar = new Ingredient("Sugar", ZERO, ZERO, HUNDRED);
|
||||||
|
|
||||||
|
assertEquals("Sugar", sugar.name);
|
||||||
|
assertEquals(ZERO, sugar.proteinPer100g);
|
||||||
|
assertEquals(ZERO, sugar.fatPer100g);
|
||||||
|
assertEquals(HUNDRED, sugar.carbsPer100g);
|
||||||
|
assertEquals(0L, sugar.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkConstructorIngredientIfEverything0() {
|
||||||
|
Ingredient water = new Ingredient("Water", ZERO, ZERO, ZERO);
|
||||||
|
|
||||||
|
assertEquals(ZERO, water.kcalPer100g());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void checkConstructorIngredientIfEverything100() {
|
||||||
|
Ingredient test = new Ingredient("Test", PROTEIN_10, FAT_5, CARBS_20);
|
||||||
|
|
||||||
|
assertEquals(EXPECTED_KCAL_165, test.kcalPer100g());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
4
commons/src/test/java/commons/RecipeIngredientTest.java
Normal file
4
commons/src/test/java/commons/RecipeIngredientTest.java
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
package commons;
|
||||||
|
//should i do it or wait for lines for next week
|
||||||
|
public class RecipeIngredientTest {
|
||||||
|
}
|
||||||
74
commons/src/test/java/commons/UnitTest.java
Normal file
74
commons/src/test/java/commons/UnitTest.java
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package commons;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class UnitTest {
|
||||||
|
|
||||||
|
//stupid magic numbers
|
||||||
|
private static final double GRAMS = 1.0;
|
||||||
|
private static final double KILOGRAMS = 1000.0;
|
||||||
|
private static final double MILLILITERS = 1.0;
|
||||||
|
private static final double LITERS = 1000.0;
|
||||||
|
private static final double TABLESPOONS = 15.0;
|
||||||
|
private static final double TEASPOONS = 5.0;
|
||||||
|
private static final double CUPS = 240.0;
|
||||||
|
private static final double PIECES = 1.0;
|
||||||
|
|
||||||
|
private static final double NoMeaningfulValue = 0.0;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void formalUnitMarkedFormal(){
|
||||||
|
assertTrue(Unit.GRAM.isFormal());
|
||||||
|
assertTrue(Unit.KILOGRAM.isFormal());
|
||||||
|
assertTrue(Unit.LITER.isFormal());
|
||||||
|
assertTrue(Unit.CUP.isFormal());
|
||||||
|
assertTrue(Unit.MILLILITER.isFormal());
|
||||||
|
assertTrue(Unit.PIECE.isFormal());
|
||||||
|
assertTrue(Unit.TABLESPOON.isFormal());
|
||||||
|
assertTrue(Unit.TEASPOON.isFormal());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void informalUnitAreNotFormal() {
|
||||||
|
assertFalse(Unit.PINCH.isFormal());
|
||||||
|
assertFalse(Unit.HANDFUL.isFormal());
|
||||||
|
assertFalse(Unit.TO_TASTE.isFormal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void conversionIsCorrect() {
|
||||||
|
assertEquals(GRAMS, Unit.GRAM.conversionFactor);
|
||||||
|
assertEquals(KILOGRAMS, Unit.KILOGRAM.conversionFactor);
|
||||||
|
assertEquals(LITERS, Unit.LITER.conversionFactor);
|
||||||
|
assertEquals(CUPS, Unit.CUP.conversionFactor);
|
||||||
|
assertEquals(MILLILITERS, Unit.MILLILITER.conversionFactor);
|
||||||
|
assertEquals(PIECES, Unit.PIECE.conversionFactor);
|
||||||
|
assertEquals(TABLESPOONS, Unit.TABLESPOON.conversionFactor);
|
||||||
|
assertEquals(TEASPOONS, Unit.TEASPOON.conversionFactor);
|
||||||
|
|
||||||
|
assertEquals(NoMeaningfulValue, Unit.PINCH.conversionFactor);
|
||||||
|
assertEquals(NoMeaningfulValue, Unit.HANDFUL.conversionFactor);
|
||||||
|
assertEquals(NoMeaningfulValue, Unit.TO_TASTE.conversionFactor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void toStringReturnsName(){
|
||||||
|
assertEquals("GRAM", Unit.GRAM.toString());
|
||||||
|
assertEquals("KILOGRAM", Unit.KILOGRAM.toString());
|
||||||
|
assertEquals("LITER", Unit.LITER.toString());
|
||||||
|
assertEquals("CUP", Unit.CUP.toString());
|
||||||
|
assertEquals("MILLILITER", Unit.MILLILITER.toString());
|
||||||
|
assertEquals("PIECE", Unit.PIECE.toString());
|
||||||
|
assertEquals("TABLESPOON", Unit.TABLESPOON.toString());
|
||||||
|
assertEquals("TEASPOON", Unit.TEASPOON.toString());
|
||||||
|
|
||||||
|
assertEquals("PINCH", Unit.PINCH.toString());
|
||||||
|
assertEquals("HANDFUL", Unit.HANDFUL.toString());
|
||||||
|
assertEquals("TO_TASTE", Unit.TO_TASTE.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
11
server/src/main/java/server/IngredientRepository.java
Normal file
11
server/src/main/java/server/IngredientRepository.java
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
package server;
|
||||||
|
|
||||||
|
import commons.Ingredient;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IngredientRepository extends JpaRepository<Ingredient, Long> {
|
||||||
|
List<Ingredient> findAllByOrderByNameAsc();
|
||||||
|
}
|
||||||
|
|
||||||
11
server/src/main/java/server/RecipeIngredientRepository.java
Normal file
11
server/src/main/java/server/RecipeIngredientRepository.java
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
package server;
|
||||||
|
|
||||||
|
import commons.RecipeIngredient;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface RecipeIngredientRepository extends JpaRepository<RecipeIngredient, Long> {
|
||||||
|
|
||||||
|
long countByIngredientId(long ingredientId);
|
||||||
|
|
||||||
|
void deleteByIngredientId(long ingredientId);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue