diff --git a/doc/TechnicalSpecification.md b/doc/TechnicalSpecification.md index 4f03d6d..f9a28b4 100644 --- a/doc/TechnicalSpecification.md +++ b/doc/TechnicalSpecification.md @@ -347,6 +347,12 @@ found in **OTHER** section. - [ ] Read (Required, Default: F) boolean - [ ] Created (Required) date/time stamp +- [x] RecipeOfTheWeek: Represents the recipe of the week. + - [x] ID (PK) Serial + - [x] RecipeId (FK: Recipe.Id, Required) Serial + - [x] Score (Required) float (Computed score) + - [x] Created (Required) date/time stamp (serves as the validity) + '**': Not sure implementation diff --git a/internal/infrastructure/database/migrations/009_create_recipe_of_the_week_table.sql b/internal/infrastructure/database/migrations/009_create_recipe_of_the_week_table.sql new file mode 100644 index 0000000..0f8277a --- /dev/null +++ b/internal/infrastructure/database/migrations/009_create_recipe_of_the_week_table.sql @@ -0,0 +1,14 @@ +-- Author: Hayden Hargreaves (hhargreaves2006@gmail.com) +-- Desc: Create the recipe of the week table. +-- Date: 07/26/2025 + +BEGIN; + +CREATE TABLE IF NOT EXISTS RecipeOfTheWeek ( + Id SERIAL PRIMARY KEY NOT NULL, + RecipeId INTEGER NOT NULL REFERENCES recipes(id), + Score NUMERIC(10, 4) NOT NULL, + Created TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +COMMIT; diff --git a/internal/infrastructure/database/migrations/010_create_recipe_of_the_week_procedure.sql b/internal/infrastructure/database/migrations/010_create_recipe_of_the_week_procedure.sql new file mode 100644 index 0000000..0ddcb6f --- /dev/null +++ b/internal/infrastructure/database/migrations/010_create_recipe_of_the_week_procedure.sql @@ -0,0 +1,41 @@ +-- Author: Hayden Hargreaves (hhargreaves2006@gmail.com) +-- Desc: Create the recipe of the week stored procedure. +-- Date: 07/26/2025 + +CREATE OR REPLACE PROCEDURE calculate_recipe_of_the_week_procedure() +LANGUAGE plpgsql +AS $$ +BEGIN + -- Insert the highest-scoring recipe from the last 7 days into daily_top_recipes + INSERT INTO RecipeOfTheWeek (RecipeId, Score, Created) + SELECT + e.Entity AS RecipeId, + ( + -- Weights can be configured here + SUM(CASE WHEN e.Type = 'viewed' THEN 1 ELSE 0 END) * 0.20 + + SUM(CASE WHEN e.Type = 'made' THEN 1 ELSE 0 END) * 0.40 + + SUM(CASE WHEN e.Type = 'liked' THEN 1 ELSE 0 END) * 0.30 + + SUM(CASE WHEN e.Type = 'shared' THEN 1 ELSE 0 END) * 0.10 + ) AS Score, + NOW() + FROM + Engagements e + WHERE + e.Created >= NOW() - INTERVAL '7 days' + AND e.Entity IS NOT NULL + GROUP BY e.Entity + ORDER BY Score DESC + LIMIT 1; + + RAISE NOTICE 'Successfully calculated and stored the top recipe for the day.'; + + + EXCEPTION + WHEN NO_DATA_FOUND THEN + -- Handle cases where no engagements are found in the last 7 days + RAISE NOTICE 'No engagement data found for the last 7 days to calculate a top recipe.'; + WHEN OTHERS THEN + -- Catch any other potential errors and re-raise them after logging + RAISE EXCEPTION 'An error occurred during top recipe calculation: %', SQLERRM; +END; +$$;