Business logic of the app

#' Business logic of the app
#'
#' @description
#' Responsible for the data wrangling, generation of text and charts and (it might be a bit of overkill in this app) filtering for the user interface. See [Using R6 as data storage](https://engineering-shiny.org/common-app-caveats.html#using-r6-as-data-storage) for more information on this solution.
#' 
#' @export
BusinessLogic <- R6::R6Class(
  "BusinessLogic",
  public = list(
    #' @field months Month numbers and their names, on the app selecting the month's name will return the month's number.
    months =   c(
    "January" = 1,
    "February" = 2,
    "March" = 3,
    "April" = 4,
    "May" = 5,
    "June" = 6,
    "July" = 7,
    "August" = 8,
    "September" = 9,
    "October" = 10,
    "November" = 11,
    "December" = 12
  ),
    #' @field metrics Available metrics with better looking names for the app.
    metrics = c(
      "Departure delay" = "dep_delay",
      "Arrival delay" = "arr_delay"
    ),
    #' @field data Will store the data (more useful for bigger apps).
    data = NULL,
    #' @field unique_carriers Available carriers (more useful in the case of a database with more carriers being added over time).
    unique_carriers = NULL,
    #' @field results Where results (title and text for the page and the chart itself) are stored.
    results = list(
      title = NULL,
      text = NULL,
      chart = NULL
    ),
    #' @description
    #' Create a new business logic object.
    #' @return A new `BusinessLogic` object.
    initialize = function() {
      self$data <- nycflights13::flights

      self$unique_carriers <- nycflights13::airlines %>%
        dplyr::mutate(name = name %>%
                        stringr::str_remove_all(" Inc.") %>%
                        stringr::str_remove_all(" Corporation"))
    },
    #' @description
    #' Generate results, all parameters come directly from the user interface of the app.
    #' @param carrier_filter Carrier for report.
    #' @param month_filter Month for report.
    #' @param metric_filter Metric for report.
    #' @param threshold Threshold for report.
    generate_results = function(
      carrier_filter,
      month_filter,
      metric_filter,
      threshold
    ) {

      carrier_code <- self$unique_carriers %>%
        dplyr::filter(name == carrier_filter) %>%
        dplyr::pull(carrier)

      filtered_data <- self$data %>%
        dplyr::filter(
          carrier == carrier_code,
          month == month_filter,
          .data[[metric_filter]] >= 0
        ) %>%
        dplyr::group_by(day) %>%
        dplyr::summarize(metric = mean(.data[[metric_filter]], na.rm = TRUE))

      month <- self$months[month_filter] %>%
        names()

      carrier <- carrier_filter


      number_of_days <- filtered_data %>%
        dplyr::filter(metric > threshold) %>%
        nrow()

      metric <- dplyr::if_else(
        metric_filter == "dep_delay",
        "departures",
        "arrivals"
      )

      self$results$title <- "{month}: {carrier}" %>%
        glue::glue()

      self$results$text <- "In {month} {carrier} had {number_of_days} days with {metric} delayed by more than {threshold} minutes." %>%
        glue::glue()

      self$results$chart <- filtered_data %>%
        dplyr::mutate(day = factor(day)) %>%
        ggplot2::ggplot(ggplot2::aes(day, metric)) +
        ggplot2::geom_line(group = 1) +
        ggplot2::geom_hline(
          yintercept = threshold,
          lty = "dashed",
          color = "red"
        ) +
        ggplot2::labs(
          title = "Average {metric} delay per day for {carrier} in {month}" %>%
            glue::glue(),
          x = "Day of the month",
          y = "Average delay [minutes]"
        )
    }
  )
)
business_logic <- BusinessLogic$new()

business_logic$generate_results("Endeavor Air", 1, "arr_delay", 30)

business_logic$results$title

business_logic$results$text

business_logic$results$chart
test_that("business_logic works", {

  business_logic <- BusinessLogic$new()

  business_logic$generate_results("Endeavor Air", 1, "arr_delay", 30)

  expect_s3_class(business_logic, "R6")

  expect_s3_class(business_logic, "BusinessLogic")

  expect_identical(business_logic$data, nycflights13::flights)

  expect_identical(business_logic$results$title,
    "January: Endeavor Air")

  expect_identical(business_logic$results$text,
    "In January Endeavor Air had 16 days with arrivals delayed by more than 30 minutes.")

  vdiffr::expect_doppelganger("Results chart 1", business_logic$results$chart)

  business_logic$generate_results("United Air Lines", 7, "dep_delay", 12)

  expect_identical(business_logic$results$text,
    "In July United Air Lines had 30 days with departures delayed by more than 12 minutes.")

  vdiffr::expect_doppelganger("Results chart 2", business_logic$results$chart)

})
# Run but keep eval=FALSE to avoid infinite loop
# Execute in the console directly
fusen::inflate(
  flat_file = "dev/flat_business-logic.Rmd",
  vignette_name = NA,
  check = FALSE
)


ggpinto/flights.dashboard documentation built on March 24, 2022, 12:38 p.m.