expenditure_concept = direct|total in cog_spending(), refused in the cross-government verbs #10
@@ -143,6 +143,10 @@ cog_find_peers <- function(target_govid,
|
||||
#' @param per_capita Default `TRUE` — peer compare usually normalizes by
|
||||
#' population.
|
||||
#' @param adjust_to_year Integer base year for CPI-U conversion or `NULL`.
|
||||
#' @param expenditure_concept `"direct"` (default) or `"total"`. Currently only
|
||||
#' `"direct"` is accepted; the `"total"` option exists in [cog_spending()] for
|
||||
#' single-government queries but cannot be used here because combining Total
|
||||
#' across peer sets counts intergovernmental transfers twice.
|
||||
#' @return Tibble matching [cog_spending()]'s columns, plus a `role`
|
||||
#' column taking values `"target"`, `"peer"`, `"summary_p25"`,
|
||||
#' `"summary_p50"`, or `"summary_p75"`, `target_rank` (target's rank
|
||||
@@ -153,8 +157,13 @@ cog_find_peers <- function(target_govid,
|
||||
#' `cohort_year`, and `cohort_govids`.
|
||||
#' @export
|
||||
cog_peer_compare <- function(target_govid, peers, category, years,
|
||||
per_capita = TRUE, adjust_to_year = NULL) {
|
||||
per_capita = TRUE, adjust_to_year = NULL,
|
||||
expenditure_concept = c("direct", "total")) {
|
||||
call <- match.call()
|
||||
expenditure_concept <- match.arg(expenditure_concept)
|
||||
if (identical(expenditure_concept, "total")) {
|
||||
.abort_concept_not_aggregatable("cog_peer_compare")
|
||||
}
|
||||
if (!is.character(target_govid) || length(target_govid) != 1L) {
|
||||
cli::cli_abort("`target_govid` must be a length-1 character string.")
|
||||
}
|
||||
|
||||
+12
-1
@@ -25,6 +25,12 @@
|
||||
#' population from `gov_population_yearly`. Govs with missing population
|
||||
#' are excluded from the result.
|
||||
#' @param adjust_to_year Integer base year for CPI-U conversion, or `NULL`.
|
||||
#' @param expenditure_concept `"direct"` (default) or `"total"`. Currently only
|
||||
#' `"direct"` is accepted; the `"total"` option exists in [cog_spending()] for
|
||||
#' single-government queries but cannot be used here because combining Total
|
||||
#' across multiple layers of government double-counts intergovernmental
|
||||
#' transfers (a state's payment to a school district is the same dollar the
|
||||
#' district reports as its own Direct spending).
|
||||
#' @return Tibble with columns `year`, `layer`, `canonical_govid`, `gov_name`,
|
||||
#' `spend_subtype`, `category`, `amt_nominal`, optional `amt_real` /
|
||||
#' `amt_per_capita_nominal` / `amt_per_capita_real`, optional `pop_source`,
|
||||
@@ -33,8 +39,13 @@
|
||||
#' and `rollup$included_govids` / `rollup$excluded_govids`.
|
||||
#' @export
|
||||
cog_geographic_rollup <- function(govids, category, years,
|
||||
per_capita = FALSE, adjust_to_year = NULL) {
|
||||
per_capita = FALSE, adjust_to_year = NULL,
|
||||
expenditure_concept = c("direct", "total")) {
|
||||
call <- match.call()
|
||||
expenditure_concept <- match.arg(expenditure_concept)
|
||||
if (identical(expenditure_concept, "total")) {
|
||||
.abort_concept_not_aggregatable("cog_geographic_rollup")
|
||||
}
|
||||
.validate_rollup_layers(govids)
|
||||
|
||||
govids <- lapply(govids, .coerce_govid_input, arg = "govids[[layer]]")
|
||||
|
||||
@@ -82,6 +82,22 @@ cog_spending <- function(govid, years, category = NULL,
|
||||
)
|
||||
}
|
||||
|
||||
#' @noRd
|
||||
.abort_concept_not_aggregatable <- function(verb) {
|
||||
cli::cli_abort(c(
|
||||
"{.code expenditure_concept = \"total\"} cannot be used in {.fn {verb}}.",
|
||||
"*" = "Use {.code expenditure_concept = \"direct\"} (the default) for any \\
|
||||
comparison or sum that spans more than one government.",
|
||||
"i" = "Why: Census \"Total\" is a government's own Direct spending PLUS the \\
|
||||
money it hands to other governments. The receiving government reports \\
|
||||
that same dollar again as its own Direct when it actually spends it, \\
|
||||
so combining Total across governments double-counts intergovernmental \\
|
||||
transfers.",
|
||||
"i" = "For one government's own Total, use \\
|
||||
{.code cog_spending(expenditure_concept = \"total\")}."
|
||||
), class = "uscogdata_concept_not_aggregatable")
|
||||
}
|
||||
|
||||
#' @noRd
|
||||
.verb_spendrev <- function(verb, view_base, subtype_col, flow_prefixes, call,
|
||||
govid, years, category,
|
||||
|
||||
@@ -9,7 +9,8 @@ cog_geographic_rollup(
|
||||
category,
|
||||
years,
|
||||
per_capita = FALSE,
|
||||
adjust_to_year = NULL
|
||||
adjust_to_year = NULL,
|
||||
expenditure_concept = c("direct", "total")
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
@@ -27,6 +28,13 @@ population from `gov_population_yearly`. Govs with missing population
|
||||
are excluded from the result.}
|
||||
|
||||
\item{adjust_to_year}{Integer base year for CPI-U conversion, or `NULL`.}
|
||||
|
||||
\item{expenditure_concept}{`"direct"` (default) or `"total"`. Currently only
|
||||
`"direct"` is accepted; the `"total"` option exists in [cog_spending()] for
|
||||
single-government queries but cannot be used here because combining Total
|
||||
across multiple layers of government double-counts intergovernmental
|
||||
transfers (a state's payment to a school district is the same dollar the
|
||||
district reports as its own Direct spending).}
|
||||
}
|
||||
\value{
|
||||
Tibble with columns `year`, `layer`, `canonical_govid`, `gov_name`,
|
||||
|
||||
@@ -10,7 +10,8 @@ cog_peer_compare(
|
||||
category,
|
||||
years,
|
||||
per_capita = TRUE,
|
||||
adjust_to_year = NULL
|
||||
adjust_to_year = NULL,
|
||||
expenditure_concept = c("direct", "total")
|
||||
)
|
||||
}
|
||||
\arguments{
|
||||
@@ -27,6 +28,11 @@ cog_peer_compare(
|
||||
population.}
|
||||
|
||||
\item{adjust_to_year}{Integer base year for CPI-U conversion or `NULL`.}
|
||||
|
||||
\item{expenditure_concept}{`"direct"` (default) or `"total"`. Currently only
|
||||
`"direct"` is accepted; the `"total"` option exists in [cog_spending()] for
|
||||
single-government queries but cannot be used here because combining Total
|
||||
across peer sets counts intergovernmental transfers twice.}
|
||||
}
|
||||
\value{
|
||||
Tibble matching [cog_spending()]'s columns, plus a `role`
|
||||
|
||||
@@ -186,3 +186,44 @@ test_that(".verb_spendrev rejects expenditure_concept = 'total' for a non-spendi
|
||||
class = "uscogdata_expenditure_concept_unsupported"
|
||||
)
|
||||
})
|
||||
|
||||
test_that("cog_geographic_rollup refuses expenditure_concept = 'total'", {
|
||||
expect_error(
|
||||
cog_geographic_rollup(
|
||||
govids = list(state = "010000226085"),
|
||||
category = "Police", years = 2019,
|
||||
expenditure_concept = "total"
|
||||
),
|
||||
class = "uscogdata_concept_not_aggregatable"
|
||||
)
|
||||
})
|
||||
|
||||
test_that("cog_peer_compare refuses expenditure_concept = 'total'", {
|
||||
expect_error(
|
||||
cog_peer_compare(
|
||||
target_govid = "010000226085", peers = "010000226085",
|
||||
category = "Police", years = 2019,
|
||||
expenditure_concept = "total"
|
||||
),
|
||||
class = "uscogdata_concept_not_aggregatable"
|
||||
)
|
||||
})
|
||||
|
||||
test_that("the refusal message names the fix and the reason", {
|
||||
err <- tryCatch(
|
||||
cog_geographic_rollup(govids = list(state = "010000226085"),
|
||||
category = "Police", years = 2019,
|
||||
expenditure_concept = "total"),
|
||||
condition = function(e) e
|
||||
)
|
||||
msg <- paste(conditionMessage(err), collapse = " ")
|
||||
expect_match(msg, "direct")
|
||||
expect_match(msg, "double-count|double count")
|
||||
})
|
||||
|
||||
test_that("both cross-government verbs still accept the direct default", {
|
||||
expect_no_error(
|
||||
cog_geographic_rollup(govids = list(state = "010000226085"),
|
||||
category = "Police", years = 2019)
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user