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
|
#' @param per_capita Default `TRUE` — peer compare usually normalizes by
|
||||||
#' population.
|
#' population.
|
||||||
#' @param adjust_to_year Integer base year for CPI-U conversion or `NULL`.
|
#' @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`
|
#' @return Tibble matching [cog_spending()]'s columns, plus a `role`
|
||||||
#' column taking values `"target"`, `"peer"`, `"summary_p25"`,
|
#' column taking values `"target"`, `"peer"`, `"summary_p25"`,
|
||||||
#' `"summary_p50"`, or `"summary_p75"`, `target_rank` (target's rank
|
#' `"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`.
|
#' `cohort_year`, and `cohort_govids`.
|
||||||
#' @export
|
#' @export
|
||||||
cog_peer_compare <- function(target_govid, peers, category, years,
|
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()
|
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) {
|
if (!is.character(target_govid) || length(target_govid) != 1L) {
|
||||||
cli::cli_abort("`target_govid` must be a length-1 character string.")
|
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
|
#' population from `gov_population_yearly`. Govs with missing population
|
||||||
#' are excluded from the result.
|
#' are excluded from the result.
|
||||||
#' @param adjust_to_year Integer base year for CPI-U conversion, or `NULL`.
|
#' @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`,
|
#' @return Tibble with columns `year`, `layer`, `canonical_govid`, `gov_name`,
|
||||||
#' `spend_subtype`, `category`, `amt_nominal`, optional `amt_real` /
|
#' `spend_subtype`, `category`, `amt_nominal`, optional `amt_real` /
|
||||||
#' `amt_per_capita_nominal` / `amt_per_capita_real`, optional `pop_source`,
|
#' `amt_per_capita_nominal` / `amt_per_capita_real`, optional `pop_source`,
|
||||||
@@ -33,8 +39,13 @@
|
|||||||
#' and `rollup$included_govids` / `rollup$excluded_govids`.
|
#' and `rollup$included_govids` / `rollup$excluded_govids`.
|
||||||
#' @export
|
#' @export
|
||||||
cog_geographic_rollup <- function(govids, category, years,
|
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()
|
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)
|
.validate_rollup_layers(govids)
|
||||||
|
|
||||||
govids <- lapply(govids, .coerce_govid_input, arg = "govids[[layer]]")
|
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
|
#' @noRd
|
||||||
.verb_spendrev <- function(verb, view_base, subtype_col, flow_prefixes, call,
|
.verb_spendrev <- function(verb, view_base, subtype_col, flow_prefixes, call,
|
||||||
govid, years, category,
|
govid, years, category,
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ cog_geographic_rollup(
|
|||||||
category,
|
category,
|
||||||
years,
|
years,
|
||||||
per_capita = FALSE,
|
per_capita = FALSE,
|
||||||
adjust_to_year = NULL
|
adjust_to_year = NULL,
|
||||||
|
expenditure_concept = c("direct", "total")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
\arguments{
|
\arguments{
|
||||||
@@ -27,6 +28,13 @@ population from `gov_population_yearly`. Govs with missing population
|
|||||||
are excluded from the result.}
|
are excluded from the result.}
|
||||||
|
|
||||||
\item{adjust_to_year}{Integer base year for CPI-U conversion, or `NULL`.}
|
\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{
|
\value{
|
||||||
Tibble with columns `year`, `layer`, `canonical_govid`, `gov_name`,
|
Tibble with columns `year`, `layer`, `canonical_govid`, `gov_name`,
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ cog_peer_compare(
|
|||||||
category,
|
category,
|
||||||
years,
|
years,
|
||||||
per_capita = TRUE,
|
per_capita = TRUE,
|
||||||
adjust_to_year = NULL
|
adjust_to_year = NULL,
|
||||||
|
expenditure_concept = c("direct", "total")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
\arguments{
|
\arguments{
|
||||||
@@ -27,6 +28,11 @@ cog_peer_compare(
|
|||||||
population.}
|
population.}
|
||||||
|
|
||||||
\item{adjust_to_year}{Integer base year for CPI-U conversion or `NULL`.}
|
\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{
|
\value{
|
||||||
Tibble matching [cog_spending()]'s columns, plus a `role`
|
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"
|
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