Repository navigation
feat(api): export cog_suggestions() (#75) - #1
Conversation
The candidate-recipe query in .query_candidate_recipes() used SELECT
DISTINCT with no ORDER BY, and .build_suggestions() emits suggestions in
candidate order. DuckDB returns DISTINCT rows in whatever order its
parallel hash aggregate finishes, so two identical cog_spending() or
cog_revenue() calls could list the same suggestions in different orders.
The query now ends in ORDER BY recipe_id.
On the bundled fixture, cog_spending("010000226085", 2011, category =
"All Categories") listed corrections_other_capital_combined before
corrections_combined; both new tests fail against the previous code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qbe6u2h83wgZdTgJgE4Xh5
cog_suggestions(govid, years, category, flow, concept, years_present) returns the list that cog_spending() and cog_revenue() attach as attr(x, "provenance")$suggestions, given the years the caller's rows cover. A caller can run a verb once with no category, filter the rows itself, and build the suggestions for a category only when it needs them, without reaching into .build_suggestions() and six other internal names. It validates every argument before opening a session, with cli errors whose classes match the verbs' where one exists (uscogdata_invalid_expenditure_concept, uscogdata_invalid_revenue_concept, uscogdata_all_categories_not_combinable) and a new uscogdata_invalid_flow. It resolves the verbs' default basis the way .verb_spendrev() does, so it returns an empty list on a schema_version < 5 corpus, and it does not print the suggestion message. Tests check that it returns exactly the verbs' list for empty_year and suppressed_component fires, a multi-government cohort, a data-frame govid, both revenue concepts, "All Categories" under each concept, and expenditure_concept = "total" given Direct-leg years. Closes #75 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qbe6u2h83wgZdTgJgE4Xh5
|
Thanks for this — and one thing worth knowing before it happens. This repository is a mirror. Development happens on Gitea at Because that merge preserves your commits at their original SHAs, GitHub will
If it is not going to be merged, you will get an actual reply saying so. Substantial contributions get a Full details: CONTRIBUTING.md. |
Gitea issue #75
What changed
New export:
cog_suggestions(govid, years, category, flow = c("spending", "revenue"), concept = NULL, years_present)(R/suggestions.R)It returns exactly the list that
cog_spending()/cog_revenue()attach asattr(x, "provenance")$suggestions, given the years the caller's rows cover. Internally it is a thin wrapper over.build_suggestions()that makes the same call.verb_spendrev()makes, so callers no longer need the seven internal names listed in the issue.flowselects the verb. Its view base, subtype column and flow prefixes live in a small.SUGGESTION_FLOWStable next to the function.conceptisexpenditure_conceptfor spending orrevenue_conceptfor revenue.NULLresolves to the verb's own default ("primary"/"general"). It only changes the result forcategory = "All Categories", where it sets the candidate subtype scope.basisis resolved exactly as.verb_spendrev()resolves an unsetbasis. On aschema_version < 5corpus that means"raw", and the result islist(), matching the verbs..ensure_session()and usesclierrors. Classes match the verbs where one exists (uscogdata_invalid_expenditure_concept,uscogdata_invalid_revenue_concept,uscogdata_all_categories_not_combinable).uscogdata_invalid_flowis new.Stable order (separate commit, d74fb62).
.query_candidate_recipes()usedSELECT DISTINCTwith noORDER BY, and.build_suggestions()emits suggestions in candidate order. The query now ends inORDER BY recipe_id. The sort is inside.build_suggestions()'s path, so the verbs'provenance$suggestionsorder changes too, and I ran the full suite (results below).Also updated:
NAMESPACE,man/cog_suggestions.Rd(generated with roxygen2 7.3.3, matchingRoxygenNote; no other.Rdchanged),NEWS.mdunder a new# uscogdata (development version)heading, and_pkgdown.yml(reference index, "Corpus metadata" section, aftercog_recipes).Choices to review
These follow the signature sketched in the issue, but each is a call I made:
category = NULLis refused with an explanatory error. The verbs build no suggestions without a category, so aNULLhere can only returnlist().govidonly, as a character vector or a data frame withcanonical_govid. The verbs'state/typepredicate cohort is not exposed, because the issue's signature does not include it.years_presentis required.integer(0)means "no rows".NULLis refused, so a forgotten argument cannot read as "no rows in any year". Years outsideyearsare ignored..SUGGESTION_FLOWSrestates the flow prefixes thatcog_spending()/cog_revenue()pass to.verb_spendrev(). The equivalence tests would catch drift between the two, but they are two copies of the same values.DESCRIPTIONis stillVersion: 0.4.0.NEWS.mdhas a development heading, but I left any0.4.0.9000bump to you.How it was tested
Locally, on Ubuntu 24.04 with R 4.3.3, duckdb 2.0.0 (compiled from CRAN source) and testthat 3.2.1.
Local deviation: the sandbox could not reach
extensions.duckdb.org, socog_open()'sINSTALL httpfs; LOAD httpfs;failed in every session. I ran the suite on a scratch copy of the tree with that one line removed. The fixture is a local path and no test referenceshttpfs. The patch is not in any commit, and CI runs the unpatched code.Full suite on this branch: 1,162 expectations, 0 failed, 0 warnings, 0 errors, 2 skipped. The skips are the two opt-in
test-live-corpus.Rtests.Same suite on
main(ba57f9c): 1,103 expectations, 0 failed, same 2 skips. The difference is the 59 new expectations intests/testthat/test-suggestions.R.The new tests check that
cog_suggestions()returns a listidentical()to the verb's for:empty_yearfire (withig_recipe_id)suppressed_componentfiregovidcog_revenue()under both concepts"All Categories"underprimary,directand revenuetotalexpenditure_concept = "total"given Direct-leg yearsschema_version4 corpusThey also cover silence, repeated-call identity, sorted order, and every validation error.
The order tests fail on
main's code: two failures. On the fixture,cog_spending("010000226085", 2011, category = "All Categories")listscorrections_other_capital_combinedbeforecorrections_combinedwithout the sort.pkgdown::check_pkgdown(): no problems.R CMD check (local, patched copy): results to follow in a comment.
What I could not verify
Noticed, not changed
.attach_ig_counterparts()takes the first exact-set match from an unorderedharmonization_recipesquery. On the fixture no direct-expenditure recipe has more than one match, soig_recipe_idis deterministic there. If the live catalog ever gained two matches, the choice would be arbitrary.Roxygen: list(markdown = TRUE)is absent), so backticks and[links]render literally in every.Rdpage, including this one.@noRd must not be followed by any textatR/manifest.R:130andR/views.R:124.Generated by Claude Code