Skip to content

Commit

Permalink
Lint
Browse files Browse the repository at this point in the history
  • Loading branch information
danielkjellid committed Jun 27, 2024
1 parent ad05cd4 commit 48598df
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 164 deletions.
2 changes: 2 additions & 0 deletions frontend/apps/plans/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ function PlansAppInner({ results }: PlansAppInnerProps) {
<Title weight={600}>Plans</Title>
</div>
<Table<any>
initialState={{ grouping: ['planTitle'] }}
positionToolbarAlertBanner="none"
rowIdentifier="id"
columns={[
{
Expand Down
12 changes: 8 additions & 4 deletions frontend/components/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type MRT_TableOptions,
MantineReactTable,
} from 'mantine-react-table'
import React, { useEffect, useMemo, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'

import { useCommonContext } from '../../contexts/CommonProvider'

Expand All @@ -28,6 +28,8 @@ interface TableProps<TData extends object> {
data: TData[]
actionMenuItems?: MRT_TableOptions<TData>['renderRowActionMenuItems']
onRowSelectionChange?: (selection: MRT_RowSelectionState) => void
initialState?: MRT_TableOptions<TData>['initialState']
positionToolbarAlertBanner?: MRT_TableOptions<TData>['positionToolbarAlertBanner']
}

function Table<TData extends object>({
Expand All @@ -36,6 +38,8 @@ function Table<TData extends object>({
actionMenuItems,
onRowSelectionChange,
columns,
initialState = {},
positionToolbarAlertBanner,
}: TableProps<TData>) {
const getColumnDefinitions = (cols: Column<TData>[]) => {
const columnDefinitions: MRT_ColumnDef<TData>[] = []
Expand Down Expand Up @@ -91,7 +95,7 @@ function Table<TData extends object>({
density: 'xs',
showGlobalFilter: true,
pagination: { pageSize: 25, pageIndex: 0 },
grouping: ['planTitle'],
...initialState,
}}
state={{ rowSelection: rowSelection }}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
Expand Down Expand Up @@ -124,8 +128,8 @@ function Table<TData extends object>({
withBorder: false,
shadow: 'sm',
}}
enableGrouping={true}
positionToolbarAlertBanner="none"
enableGrouping={'grouping' in initialState}
positionToolbarAlertBanner={positionToolbarAlertBanner}
/>
)
}
Expand Down
6 changes: 3 additions & 3 deletions nest/recipes/core/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from ..steps.services import Step
from .forms import RecipeCreateForm
from .records import RecipeDetailRecord, RecipeRecord
from .records import RecipeDetailRecord
from .selectors import get_recipe, get_recipes
from .services import create_recipe, edit_recipe

Expand Down Expand Up @@ -88,8 +88,8 @@ def recipe_detail_api(
return APIResponse(status="success", data=recipe)


@router.get("/", response=APIResponse[list[RecipeRecord]])
def recipe_list_api(request: HttpRequest) -> APIResponse[list[RecipeRecord]]:
@router.get("/", response=APIResponse[list[RecipeDetailRecord]])
def recipe_list_api(request: HttpRequest) -> APIResponse[list[RecipeDetailRecord]]:
"""
Get a list of all recipes in the application.
"""
Expand Down
79 changes: 50 additions & 29 deletions nest/recipes/core/selectors.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,48 @@
from nest.core.exceptions import ApplicationError
from django.db.models import QuerySet

from ...core.exceptions import ApplicationError
from ...core.types import FetchedResult
from ..ingredients.selectors import (
get_recipe_ingredient_item_groups_for_recipe,
get_recipe_ingredient_item_groups_for_recipes,
)
from ..steps.selectors import get_steps_for_recipe, get_steps_for_recipes
from ..steps.selectors import get_steps_for_recipes
from .enums import RecipeDifficulty, RecipeStatus
from .models import Recipe
from .records import (
RecipeDetailRecord,
RecipeDurationRecord,
RecipeRecord,
)
from ...core.types import FetchedResult


def get_recipe(*, pk: int) -> RecipeDetailRecord:
"""
Get a recipe instance.
"""
recipe = get_recipes(recipe_ids=[pk])[pk]
recipe = get_recipes_by_id(recipe_ids=[pk])[pk]

if not recipe:
raise ApplicationError("Recipe was not found", status_code=404)

return recipe


def get_recipes(
*, recipe_ids: list[int] | None = None
) -> FetchedResult[RecipeDetailRecord]:
def get_recipe_data(*, qs: QuerySet[Recipe]) -> FetchedResult[RecipeDetailRecord]:
"""
Get a list off all recipes.
Core selector for getting recipes. Takes a filtered queryset as parameter and
does all annotations and ordering based on that.
"""
result: FetchedResult[RecipeDetailRecord] = {}

result = {recipe_id: None for recipe_id in recipe_ids}

if not recipe_ids:
recipes = (
Recipe.objects.all()
.annotate_duration()
.annotate_num_plan_usages()
.order_by("-created_at")
)
else:
recipes = (
Recipe.objects.filter(id__in=recipe_ids)
.annotate_duration()
.annotate_num_plan_usages()
.order_by("-created_at")
)
recipes = (
qs.annotate_duration() # type: ignore
.annotate_num_plan_usages()
.order_by("-created_at")
)

relevant_recipe_ids = [recipe.id for recipe in recipes]
steps = get_steps_for_recipes(recipe_ids=relevant_recipe_ids)
recipe_ids = [recipe.id for recipe in recipes]
steps = get_steps_for_recipes(recipe_ids=recipe_ids)
ingredient_groups = get_recipe_ingredient_item_groups_for_recipes(
recipe_ids=relevant_recipe_ids
recipe_ids=recipe_ids
)

for recipe in recipes:
Expand All @@ -77,3 +69,32 @@ def get_recipes(
)

return result


def get_recipes_by_id(
*, recipe_ids: list[int]
) -> FetchedResult[RecipeDetailRecord | None]:
"""
Get a retrieved recipes based in provided Ids.
"""

qs = Recipe.objects.filter(id__in=recipe_ids)
result: FetchedResult[RecipeDetailRecord | None] = {
recipe_id: None for recipe_id in recipe_ids
}
recipes = get_recipe_data(qs=qs)

for recipe_id, recipe in recipes.items():
result[recipe_id] = recipe

return result


def get_recipes() -> list[RecipeDetailRecord]:
"""
Get a list off all recipes.
"""

qs = Recipe.objects.all()
result = get_recipe_data(qs=qs)
return [value for value in result.values() if value is not None]
8 changes: 4 additions & 4 deletions nest/recipes/plans/records.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

from pydantic import BaseModel

from nest.recipes.core.records import RecipeRecord
from nest.recipes.core.records import RecipeDetailRecord


class RecipePlanItemRecord(BaseModel):
id: int
plan_id: int
plan_title: str
recipe: RecipeRecord
recipe: RecipeDetailRecord


class RecipePlanRecord(BaseModel):
id: int
title: str
description: str
description: str | None
slug: str
from_date: datetime
from_date: datetime | None
items: list[RecipePlanItemRecord]
84 changes: 35 additions & 49 deletions nest/recipes/plans/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
from django.utils import timezone

from nest.core.types import FetchedResult
from nest.recipes.core.selectors import get_recipes
from nest.recipes.plans.models import RecipePlan, RecipePlanItem
from nest.recipes.plans.records import RecipePlanRecord, RecipePlanItemRecord
from nest.recipes.core.enums import RecipeStatus
from nest.recipes.core.models import Recipe
from nest.recipes.core.records import RecipeDetailRecord, RecipeDurationRecord
from nest.recipes.ingredients.selectors import (
get_recipe_ingredient_item_groups_for_recipes,
)
from nest.recipes.steps.selectors import get_steps_for_recipes
from nest.recipes.core.records import RecipeDetailRecord
from nest.recipes.core.selectors import get_recipe_data, get_recipes_by_id
from nest.recipes.plans.models import RecipePlan, RecipePlanItem
from nest.recipes.plans.records import RecipePlanItemRecord, RecipePlanRecord

# Have at least two weeks between recipes being used in plans.
RECIPE_GRACE_PERIOD_WEEKS = 2.0
Expand All @@ -21,77 +17,67 @@
def find_recipes_applicable_for_plan(
*, grace_period_weeks: float | None = None
) -> list[RecipeDetailRecord]:
"""
Find applicable recipes for plans. An applicable recipe is a recipe that is not
used in another plan in the defined grace period and is published.
"""
grace_period = grace_period_weeks or RECIPE_GRACE_PERIOD_WEEKS
first_possible_from_date = timezone.now() - timedelta(weeks=float(grace_period))

recipes = (
Recipe.objects.exclude(
recipes = get_recipe_data(
qs=Recipe.objects.exclude(
plan_items__recipe_plan__from_date__lt=first_possible_from_date,
)
.filter(
).filter(
status=RecipeStatus.PUBLISHED,
)
.annotate_duration()
.annotate_num_plan_usages() # type: ignore
)

recipe_ids = [recipe.id for recipe in recipes]
recipe_ingredient_item_groups = get_recipe_ingredient_item_groups_for_recipes(
recipe_ids=recipe_ids
)
recipe_steps = get_steps_for_recipes(recipe_ids=recipe_ids)

return [
RecipeDetailRecord(
id=recipe.id,
title=recipe.title,
slug=recipe.slug,
default_num_portions=recipe.default_num_portions,
search_keywords=recipe.search_keywords,
external_id=recipe.external_id,
external_url=recipe.external_url,
status=recipe.status,
status_display=recipe.get_status_display(),
difficulty=recipe.difficulty,
difficulty_display=recipe.get_difficulty_display(),
is_vegetarian=recipe.is_vegetarian,
is_pescatarian=recipe.is_pescatarian,
duration=RecipeDurationRecord.from_db_model(recipe),
glycemic_data=None,
health_score=None,
ingredient_item_groups=recipe_ingredient_item_groups[recipe.id],
steps=recipe_steps[recipe.id],
num_plan_usages=getattr(recipe, "num_plan_usages", 0),
)
for recipe in recipes
]
return list(recipes.values())


def get_recipe_plan_items_for_plan(
plan_ids: list[int]
) -> FetchedResult[list[RecipePlanItemRecord]]:
result = {plan_id: [] for plan_id in plan_ids}
"""
Get relevant recipe plan items for a recipe plan.
"""
result: FetchedResult[list[RecipePlanItemRecord]] = {
plan_id: [] for plan_id in plan_ids
}

plan_items = RecipePlanItem.objects.filter(
recipe_plan_id__in=plan_ids
).select_related("recipe_plan")

recipe_ids = [plan_item.recipe_id for plan_item in plan_items]
recipes = get_recipes(recipe_ids=recipe_ids)
recipes = get_recipes_by_id(recipe_ids=recipe_ids)

for plan_item in plan_items:
plan = plan_item.recipe_plan
recipe = recipes[plan_item.recipe_id]

if recipe is None:
continue

if plan is None:
continue

result[plan_item.recipe_plan_id].append(
RecipePlanItemRecord(
id=plan_item.id,
plan_id=plan_item.recipe_plan_id,
plan_title=plan_item.recipe_plan.title,
recipe=recipes[plan_item.recipe_id],
plan_id=plan.id,
plan_title=plan.title,
recipe=recipe,
)
)

return result


def get_recipe_plans_for_home(*, home_id: int) -> list[RecipePlanRecord]:
"""
Get all recipe plans for a specificed home.
"""
plans = RecipePlan.objects.filter(home_id=home_id).order_by("-created_at")

plan_ids = [plan.id for plan in plans]
Expand Down
Loading

0 comments on commit 48598df

Please sign in to comment.