feat: register balance_long / balance_annotated behind a column gate (#25)
This commit is contained in:
@@ -154,3 +154,36 @@ with_corpus_missing_ig_categories <- function(code) {
|
||||
}, add = TRUE)
|
||||
force(code)
|
||||
}
|
||||
|
||||
# Copy the bundled fixture to a temp dir with summary_categories.parquet
|
||||
# rewritten to DROP the balance_subtype column, then run `code` against it.
|
||||
# Models a corpus published before cog_pipeline #76/#77. schema_version is
|
||||
# left untouched deliberately: that change shipped without a version bump, so
|
||||
# column presence is the only honest signal -- this helper is what proves the
|
||||
# package keys off it. Mirrors with_corpus_missing_ig_categories().
|
||||
with_corpus_missing_balance_subtype <- function(code) {
|
||||
src <- fixture_corpus_path()
|
||||
tmp <- withr::local_tempdir(.local_envir = parent.frame())
|
||||
file.copy(list.files(src, full.names = TRUE), tmp, recursive = TRUE)
|
||||
|
||||
cats_path <- file.path(tmp, "data", "summary_categories.parquet")
|
||||
filtered_path <- file.path(tmp, "data", "summary_categories_filtered.parquet")
|
||||
write_con <- DBI::dbConnect(duckdb::duckdb())
|
||||
on.exit(DBI::dbDisconnect(write_con, shutdown = TRUE), add = TRUE)
|
||||
DBI::dbExecute(write_con, sprintf(
|
||||
"COPY (SELECT * EXCLUDE (balance_subtype) FROM read_parquet(%s))
|
||||
TO %s (FORMAT PARQUET)",
|
||||
uscogdata:::.sql_lit_chr(cats_path), uscogdata:::.sql_lit_chr(filtered_path)
|
||||
))
|
||||
file.remove(cats_path)
|
||||
file.rename(filtered_path, cats_path)
|
||||
|
||||
old_url <- Sys.getenv("USCOGDATA_URL", unset = NA)
|
||||
uscogdata:::cog_close()
|
||||
Sys.setenv(USCOGDATA_URL = paste0(tmp, "/"))
|
||||
on.exit({
|
||||
uscogdata:::cog_close()
|
||||
if (is.na(old_url)) Sys.unsetenv("USCOGDATA_URL") else Sys.setenv(USCOGDATA_URL = old_url)
|
||||
}, add = TRUE)
|
||||
force(code)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
test_that("balance views register and carry only balance codes", {
|
||||
skip_if_no_corpus()
|
||||
con <- cog_open()
|
||||
on.exit(cog_close())
|
||||
|
||||
views <- DBI::dbGetQuery(con,
|
||||
"SELECT table_name FROM information_schema.tables
|
||||
WHERE table_schema = 'main' AND table_type = 'VIEW'"
|
||||
)$table_name
|
||||
expect_true(all(c("balance_long", "balance_annotated") %in% views))
|
||||
|
||||
# Every item_code in balance_long is a category_type = 'balance' member.
|
||||
leak <- DBI::dbGetQuery(con,
|
||||
"SELECT COUNT(*) AS n FROM balance_long
|
||||
WHERE item_code NOT IN (
|
||||
SELECT item_code FROM summary_categories WHERE category_type = 'balance')"
|
||||
)$n
|
||||
expect_identical(as.integer(leak), 0L)
|
||||
|
||||
# And no aggregate row survives, mirroring revenue_long.
|
||||
agg <- DBI::dbGetQuery(con,
|
||||
"SELECT COUNT(*) AS n FROM balance_long WHERE is_aggregate"
|
||||
)$n
|
||||
expect_identical(as.integer(agg), 0L)
|
||||
|
||||
# balance_annotated exposes the subtype column the verb groups on.
|
||||
cols <- DBI::dbGetQuery(con,
|
||||
"SELECT column_name FROM information_schema.columns
|
||||
WHERE table_name = 'balance_annotated'"
|
||||
)$column_name
|
||||
expect_true(all(c("category", "category_type", "balance_subtype") %in% cols))
|
||||
})
|
||||
|
||||
test_that("balance views are skipped on a corpus without balance_subtype", {
|
||||
skip_if_no_corpus()
|
||||
with_corpus_missing_balance_subtype({
|
||||
con <- cog_open()
|
||||
on.exit(cog_close())
|
||||
views <- DBI::dbGetQuery(con,
|
||||
"SELECT table_name FROM information_schema.tables
|
||||
WHERE table_schema = 'main' AND table_type = 'VIEW'"
|
||||
)$table_name
|
||||
# Registration must SKIP them, not error -- an older corpus stays usable.
|
||||
expect_false(any(c("balance_long", "balance_annotated") %in% views))
|
||||
expect_true("revenue_long" %in% views)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user