Skip to content

feat(geocode): support "%dyncols:" for the opencage subcommands#3878

Merged
jqnatividad merged 5 commits into
masterfrom
feat-geocode-opencage-dyncols
May 21, 2026
Merged

feat(geocode): support "%dyncols:" for the opencage subcommands#3878
jqnatividad merged 5 commits into
masterfrom
feat-geocode-opencage-dyncols

Conversation

@jqnatividad
Copy link
Copy Markdown
Collaborator

Summary

The opencage/opencagenow geocode subcommands previously rejected the special %dyncols: --formatstr option (("%dyncols:" is not supported by opencage.)). They now support it — just like suggest/reverse/iplookup — dynamically adding one output column per {col_name:key} pair.

$ qsv geocode opencage address -f '%dyncols: {city:components.city}, {pc:components.postcode}' file.csv

key is any OpenCage dynamic field key: formatted, lat, lng, confidence, components.<name> or annotations.<dotted.path>.

Details

  • run() — dropped the opencage %dyncols: rejection. The general --new-column + %dyncols: conflict check still applies.
  • run_opencage() — parses & validates the %dyncols: formatstr before any API call (fails fast), appends one output column per pair, and in the row loop keeps the input row intact while appending the geocoded field values.
  • is_valid_opencage_dyncol() — new helper; a key is valid if it's formatted/lat/lng/confidence or starts with components./annotations. (mirrors what opencage_field_value resolves).
  • opencage_lookup_dyncols() — new caching lookup. Unlike opencage_lookup (which caches a single formatted string keyed by formatstr), this caches the raw first result as JSON, so the cache key is independent of which columns were requested — re-runs and duplicate queries still hit the cache.
  • USAGE updated and docs/help/geocode.md regenerated via qsv --generate-help-md.

Tests

  • 2 CI-runnable arg-validation tests (invalid %dyncols: key rejected; %dyncols: + --new-column rejected).
  • 1 #[ignore]'d live-API round-trip test (geocode_opencage_dyncols).

cargo check, cargo clippy, cargo +nightly fmt all clean. cargo test geocode_opencage — 4 CI tests pass, 6 live tests ignored as designed.

Note

The live round-trip test was not run here (no QSV_OPENCAGE_API_KEY available). Run it with a key to confirm end-to-end against the real API.

🤖 Generated with Claude Code

The opencage/opencagenow subcommands previously rejected the special
"%dyncols:" --formatstr option. They now support it, dynamically adding
one output column per "{col_name:key}" pair where key is an OpenCage
dynamic field key (formatted, lat, lng, confidence, components.* or
annotations.*).

Unlike opencage_lookup (which caches a single formatted string keyed by
formatstr), the new opencage_lookup_dyncols caches the raw first result
as JSON, so the cache key is independent of the requested columns and
re-runs/duplicate queries still hit the cache.

- run(): drop the opencage "%dyncols:" rejection (the --new-column +
  "%dyncols:" conflict check still applies)
- run_opencage(): parse & validate "%dyncols:" before any API call,
  append dyncols headers, and keep the input row intact while appending
  geocoded field values per row
- add is_valid_opencage_dyncol() and opencage_lookup_dyncols()
- USAGE & regenerated docs/help/geocode.md updated accordingly
- tests: 2 CI arg-validation tests + 1 ignored live-API test

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 20, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 7 complexity

Metric Results
Complexity 7

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

- opencage_lookup_dyncols: use a NUL byte in the dyncols cache key's
  formatstr slot so it can never collide with opencage_lookup's key
  space (a --formatstr is a CLI arg and cannot contain a NUL)
- run_opencage: reject malformed "%dyncols:" pairs (missing colon
  separator) and empty column names instead of silently dropping them
- tests: add CI coverage for the empty-pairs, malformed-pair and
  empty-col-name error paths

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the geocode opencage / geocode opencagenow subcommands to support the special --formatstr value %dyncols:, aligning OpenCage behavior with the other geocode subcommands that can dynamically append multiple output columns.

Changes:

  • Removed the prior rejection of %dyncols: for OpenCage subcommands and documented the new capability in command help.
  • Implemented %dyncols: parsing/validation for OpenCage, row output appending, and a new cache path that stores the raw first OpenCage result JSON for flexible field extraction.
  • Added CI-runnable argument-validation tests plus an ignored live API round-trip test for dyncols output.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/cmd/geocode.rs Adds OpenCage %dyncols: parsing/validation, dyncols row writing behavior, and JSON-based caching for multi-column extraction.
tests/test_geocode.rs Adds argument-validation tests for OpenCage dyncols and an ignored live API dyncols integration test.
docs/help/geocode.md Regenerates help text to document %dyncols: support for OpenCage.

Comment thread src/cmd/geocode.rs
Comment thread src/cmd/geocode.rs Outdated
Comment thread tests/test_geocode.rs Outdated
jqnatividad and others added 3 commits May 20, 2026 20:19
- is_valid_opencage_dyncol(): require a non-empty suffix after the
  components./annotations. prefix so a bare prefix fails fast with the
  "Invalid '%dyncols:' key" error instead of silently emitting an empty
  column.
- opencage_lookup_dyncols(): on the (unlikely) event JSON serialization
  of a geocoded result fails, skip caching and extract column values
  from the live result, instead of unwrap_or_default() caching an empty
  string that later decodes as a bogus, permanent zero-result.
- geocode_opencage_dyncols test: add Workdir::read_stdout_on_success so
  the command runs once (asserting success) instead of twice, where the
  second run could fail yet still emit parseable CSV.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
address roborev job 2323: the non-empty-suffix validation for
components./annotations. dyncols keys had no CI coverage. Add
geocode_opencage_dyncols_bare_prefix_rejected asserting a bare
prefix fails with the "Invalid '%dyncols:' key" error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
address roborev job 2324: the previous test combined components. and
annotations. in one formatstr, but validation short-circuits on the
first invalid key so the annotations. branch was never reached. Loop
over both prefixes as separate command invocations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jqnatividad jqnatividad merged commit 722e747 into master May 21, 2026
17 checks passed
@jqnatividad jqnatividad deleted the feat-geocode-opencage-dyncols branch May 21, 2026 00:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants