From 5907dbf35d1bab55d80150248d1876148d48290a Mon Sep 17 00:00:00 2001 From: Garrett Potter Date: Wed, 8 Jan 2025 03:56:19 +0000 Subject: [PATCH] Add nutrition query filters and tests --- .../Household/GroupMealPlanRuleForm.vue | 21 +++++++ .../test_group_mealplan_rules.py | 8 +++ .../repository_tests/test_pagination.py | 58 +++++++++++-------- 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/frontend/components/Domain/Household/GroupMealPlanRuleForm.vue b/frontend/components/Domain/Household/GroupMealPlanRuleForm.vue index 259e399ad00..5dfad408700 100644 --- a/frontend/components/Domain/Household/GroupMealPlanRuleForm.vue +++ b/frontend/components/Domain/Household/GroupMealPlanRuleForm.vue @@ -148,6 +148,27 @@ export default defineComponent({ label: i18n.tc("general.date-updated"), type: "date", }, + { + name: "nutrition.calories", + label: i18n.tc("recipe.calories"), + type: "number", + }, + { + name: "nutrition.carbohydrateContent", + label: i18n.tc("recipe.carbohydrate-content"), + type: "number", + }, + { + name: "nutrition.proteinContent", + label: i18n.tc("recipe.protein-content"), + type: "number", + }, + { + name: "nutrition.fatContent", + label: i18n.tc("recipe.fat-content"), + type: "number", + }, + ]; return { diff --git a/tests/integration_tests/user_household_tests/test_group_mealplan_rules.py b/tests/integration_tests/user_household_tests/test_group_mealplan_rules.py index 1405dbdab1a..97ac76f2d78 100644 --- a/tests/integration_tests/user_household_tests/test_group_mealplan_rules.py +++ b/tests/integration_tests/user_household_tests/test_group_mealplan_rules.py @@ -140,12 +140,20 @@ def test_group_mealplan_rules_delete(api_client: TestClient, unique_user: TestUs "qf_string, expected_code", [ ('tags.name CONTAINS ALL ["tag1","tag2"]', 200), + ("nutrition.calories >= 100", 200), + ("nutrition.fatContent <= 10", 200), + ("nutrition.proteinContent >= 40", 200), + ("nutrition.carbohydrateContent = 200", 200), ('badfield = "badvalue"', 422), ('recipe_category.id IN ["1"]', 422), ('created_at >= "not-a-date"', 422), ], ids=[ "valid qf", + "valid calorie filter", + "valid fat filter", + "valid protein filter", + "valid carb filter", "invalid field", "invalid UUID", "invalid date", diff --git a/tests/unit_tests/repository_tests/test_pagination.py b/tests/unit_tests/repository_tests/test_pagination.py index 528d774196b..61324d8a2f5 100644 --- a/tests/unit_tests/repository_tests/test_pagination.py +++ b/tests/unit_tests/repository_tests/test_pagination.py @@ -1,7 +1,7 @@ import random import time from collections import defaultdict -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from random import randint from urllib.parse import parse_qsl, urlsplit @@ -166,7 +166,10 @@ def test_pagination_guides(unique_user: TestUser): next_params: dict = dict(parse_qsl(urlsplit(random_page_of_results.next).query)) # type: ignore assert int(next_params["page"]) == random_page + 1 - prev_params: dict = dict(parse_qsl(urlsplit(random_page_of_results.previous).query)) # type: ignore + prev_params: dict = dict( + # type: ignore + parse_qsl(urlsplit(random_page_of_results.previous).query) + ) assert int(prev_params["page"]) == random_page - 1 source_params = camelize(query.model_dump()) @@ -238,7 +241,7 @@ def test_pagination_filter_null(unique_user: TestUser): user_id=unique_user.user_id, group_id=unique_user.group_id, name=random_string(), - last_made=datetime.now(timezone.utc), + last_made=datetime.now(UTC), ) ) @@ -531,7 +534,7 @@ def test_pagination_filter_datetimes( # units are created in order with increasing createdAt values units_repo, unit_1, unit_2, unit_3 = query_units - ## GT + # GT past_dt: datetime = unit_1.created_at - timedelta(seconds=1) # type: ignore dt = past_dt.isoformat() query = PaginationQuery(page=1, per_page=-1, query_filter=f'createdAt>"{dt}"') @@ -573,7 +576,7 @@ def test_pagination_filter_datetimes( unit_ids = {unit.id for unit in unit_results} assert len(unit_ids) == 0 - ## GTE + # GTE past_dt = unit_1.created_at - timedelta(seconds=1) # type: ignore dt = past_dt.isoformat() query = PaginationQuery(page=1, per_page=-1, query_filter=f'createdAt>="{dt}"') @@ -626,7 +629,7 @@ def test_pagination_filter_datetimes( ) def test_pagination_order_by_multiple(unique_user: TestUser, order_direction: OrderDirection): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) alphabet = ["a", "b", "c", "d", "e"] abbreviations = alphabet.copy() @@ -687,7 +690,7 @@ def test_pagination_order_by_multiple_directions( unique_user: TestUser, order_by_str: str, order_direction: OrderDirection ): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) alphabet = ["a", "b", "c", "d", "e"] abbreviations = alphabet.copy() @@ -735,7 +738,7 @@ def test_pagination_order_by_multiple_directions( ) def test_pagination_order_by_nested_model(unique_user: TestUser, order_direction: OrderDirection): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) alphabet = ["a", "b", "c", "d", "e"] labels = database.group_multi_purpose_labels.create_many( @@ -766,7 +769,7 @@ def test_pagination_order_by_nested_model(unique_user: TestUser, order_direction def test_pagination_order_by_doesnt_filter(unique_user: TestUser): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) label = database.group_multi_purpose_labels.create( MultiPurposeLabelSave(name=random_string(), group_id=unique_user.group_id) @@ -810,7 +813,7 @@ def test_pagination_order_by_nulls( unique_user: TestUser, null_position: OrderByNullPosition, order_direction: OrderDirection ): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) label = database.group_multi_purpose_labels.create( MultiPurposeLabelSave(name=random_string(), group_id=unique_user.group_id) @@ -916,7 +919,7 @@ def test_pagination_shopping_list_items_with_labels(unique_user: TestUser): def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser): - today = datetime.now(timezone.utc).date() + today = datetime.now(UTC).date() yesterday = today - timedelta(days=1) tomorrow = today + timedelta(days=1) @@ -936,7 +939,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser): response = api_client.post(api_routes.households_mealplans, json=data, headers=unique_user.token) assert response.status_code == 201 - ## Yesterday + # Yesterday params = { "page": 1, "perPage": -1, @@ -965,7 +968,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser): assert mealplan_today.title in fetched_mealplan_titles assert mealplan_tomorrow.title in fetched_mealplan_titles - ## Today + # Today params = { "page": 1, "perPage": -1, @@ -994,7 +997,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser): assert mealplan_today.title not in fetched_mealplan_titles assert mealplan_tomorrow.title in fetched_mealplan_titles - ## Tomorrow + # Tomorrow params = { "page": 1, "perPage": -1, @@ -1020,7 +1023,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser): assert len(response_json["items"]) == 0 - ## Day After Tomorrow + # Day After Tomorrow params = { "page": 1, "perPage": -1, @@ -1049,7 +1052,8 @@ def test_pagination_filter_booleans(query_units: tuple[RepositoryUnit, Ingredien query = PaginationQuery( page=1, per_page=-1, - query_filter=f"useAbbreviation=true AND id IN [{', '.join([str(unit.id) for unit in query_units[1:]])}]", + query_filter=f"useAbbreviation=true AND id IN [{ + ', '.join([str(unit.id) for unit in query_units[1:]])}]", ) unit_results = units_repo.page_all(query).items assert len(unit_results) == 1 @@ -1060,7 +1064,8 @@ def test_pagination_filter_advanced(query_units: tuple[RepositoryUnit, Ingredien units_repo, unit_1, unit_2, unit_3 = query_units dt = str(unit_3.created_at.isoformat()) # type: ignore - qf = f'name="test unit 1" OR (useAbbreviation=f AND (name="{unit_2.name}" OR createdAt > "{dt}"))' + qf = f'name="test unit 1" OR (useAbbreviation=f AND (name="{ + unit_2.name}" OR createdAt > "{dt}"))' query = PaginationQuery(page=1, per_page=-1, query_filter=qf) unit_results = units_repo.page_all(query).items @@ -1069,7 +1074,8 @@ def test_pagination_filter_advanced(query_units: tuple[RepositoryUnit, Ingredien assert unit_2.id in result_ids assert unit_3.id not in result_ids - qf = f'(name LIKE %_1 OR name IN ["{unit_2.name}"]) AND createdAt IS NOT NONE' + qf = f'(name LIKE %_1 OR name IN ["{ + unit_2.name}"]) AND createdAt IS NOT NONE' query = PaginationQuery(page=1, per_page=-1, query_filter=qf) unit_results = units_repo.page_all(query).items @@ -1184,7 +1190,8 @@ def test_pagination_filter_advanced_frontend_sort(unique_user: TestUser): repo = database.recipes - qf = f'recipeCategory.id IN ["{category_1.id}"] AND tools.id IN ["{tool_1.id}"]' + qf = f'recipeCategory.id IN ["{ + category_1.id}"] AND tools.id IN ["{tool_1.id}"]' query = PaginationQuery(page=1, per_page=-1, query_filter=qf) recipe_results = repo.page_all(query).items assert len(recipe_results) == 1 @@ -1197,7 +1204,8 @@ def test_pagination_filter_advanced_frontend_sort(unique_user: TestUser): assert recipe_ct0_tg2_tl2.id not in recipe_ids assert recipe_ct12_tg12_tl2.id not in recipe_ids - qf = f'recipeCategory.id CONTAINS ALL ["{category_1.id}", "{category_2.id}"] AND tags.id IN ["{tag_1.id}"]' + qf = f'recipeCategory.id CONTAINS ALL ["{category_1.id}", "{ + category_2.id}"] AND tags.id IN ["{tag_1.id}"]' query = PaginationQuery(page=1, per_page=-1, query_filter=qf) recipe_results = repo.page_all(query).items assert len(recipe_results) == 1 @@ -1210,7 +1218,8 @@ def test_pagination_filter_advanced_frontend_sort(unique_user: TestUser): assert recipe_ct0_tg2_tl2.id not in recipe_ids assert recipe_ct12_tg12_tl2.id in recipe_ids - qf = f'tags.id IN ["{tag_1.id}", "{tag_2.id}"] AND tools.id IN ["{tool_2.id}"]' + qf = f'tags.id IN ["{tag_1.id}", "{ + tag_2.id}"] AND tools.id IN ["{tool_2.id}"]' query = PaginationQuery(page=1, per_page=-1, query_filter=qf) recipe_results = repo.page_all(query).items assert len(recipe_results) == 2 @@ -1224,8 +1233,10 @@ def test_pagination_filter_advanced_frontend_sort(unique_user: TestUser): assert recipe_ct12_tg12_tl2.id in recipe_ids qf = ( - f'recipeCategory.id CONTAINS ALL ["{category_1.id}", "{category_2.id}"]' - f'AND tags.id IN ["{tag_1.id}", "{tag_2.id}"] AND tools.id IN ["{tool_1.id}", "{tool_2.id}"]' + f'recipeCategory.id CONTAINS ALL ["{ + category_1.id}", "{category_2.id}"]' + f'AND tags.id IN ["{tag_1.id}", "{ + tag_2.id}"] AND tools.id IN ["{tool_1.id}", "{tool_2.id}"]' ) query = PaginationQuery(page=1, per_page=-1, query_filter=qf) recipe_results = repo.page_all(query).items @@ -1265,6 +1276,7 @@ def test_pagination_filter_advanced_frontend_sort(unique_user: TestUser): 'group.preferences.badAttribute="test value"', id="bad double nested attribute", ), + pytest.param('nutrition.calories="test"', id="comparing int to string"), ], ) def test_malformed_query_filters(api_client: TestClient, unique_user: TestUser, qf: str):