Skip to content

feat(geocode): add OpenCage online geocoding subcommands (#1295)#3876

Merged
jqnatividad merged 2 commits into
masterfrom
geocode-opencage-support
May 20, 2026
Merged

feat(geocode): add OpenCage online geocoding subcommands (#1295)#3876
jqnatividad merged 2 commits into
masterfrom
geocode-opencage-support

Conversation

@jqnatividad

Copy link
Copy Markdown
Collaborator

Closes #1295.

Adds opencage and opencagenow subcommands to the geocode command for online forward (address → coordinates) and reverse (coordinates → address) geocoding via the OpenCage Geocoding API. The existing offline subcommands (suggest/reverse/countryinfo/iplookup) are unchanged.

Per the issue's 2026-05-20 comment, this brings OpenCage support into OSS qsv (out of "qsv pro 2.x") for the DataPusher+/Prefect work — the offline GeoNames engine cannot geocode real street addresses.

What's included

  • New subcommands: qsv geocode opencage <column> and qsv geocode opencagenow <location>. The query column may hold an address (forward) or a lat,long coordinate (reverse); the mode is auto-detected per row (--reverse forces reverse).
  • Direct REST integration: calls the OpenCage JSON API with qsv's existing async reqwest client (rustls, honors --timeout). The geocoding crate was evaluated but rejected — it is unmaintained, pins reqwest 0.11, and pulls in native-tls/OpenSSL, breaking qsv's rustls-only policy. No new crate dependency is added.
  • Persistent caching: OpenCage's TOS explicitly permits caching, so successful lookups go to an on-disk cache (cached::DiskCache) keyed on query+language+country+format, plus in-run de-duplication. Controlled by --cache-ttl (default 14 days) and --no-cache.
  • Rate limiting: a governor rate limiter (--rate-limit, default 1 req/sec — the free-tier limit) over a sequential row loop, routed entirely around the offline rayon pipeline so the offline path is untouched.
  • API key: --api-key flag or QSV_OPENCAGE_API_KEY env var (flag wins); missing key is a clean usage error.
  • Formatting: OpenCage-specific %-formats (%formatted, %city, %country, %json, …) and dotted-key dynamic templating ({components.city}, {annotations.timezone.name}).
  • governor added to the geocode Cargo feature.

Testing

  • qsv, qsvdp, and qsvmcp all build; clippy and cargo +nightly fmt are clean.
  • CI tests cover argument validation (missing API key, --admin1 rejection).
  • Live-API tests are #[ignore]'d. They have not been run — verifying the actual geocoding round-trip requires an OpenCage API key:
    QSV_OPENCAGE_API_KEY=<key> cargo test -F all_features geocode_opencage -- --ignored
    

🤖 Generated with Claude Code

Add `opencage` and `opencagenow` subcommands to the `geocode` command for
online forward (address) and reverse (coordinate) geocoding via the OpenCage
Geocoding API. The offline subcommands (suggest/reverse/countryinfo/iplookup)
are unchanged.

- calls the OpenCage REST API directly with the async reqwest client
  (rustls, honors --timeout); no new crate dependency
- persistent on-disk result cache (OpenCage's TOS permits caching) plus
  in-run de-duplication; controlled by --cache-ttl / --no-cache
- governor rate limiter (--rate-limit, default 1/sec) over a sequential
  row loop, routed around the offline rayon pipeline
- API key via --api-key flag or QSV_OPENCAGE_API_KEY env var
- OpenCage-specific %-formats and dotted-key dynamic templating
  ({components.city}, {annotations.timezone.name})
- governor added to the geocode feature in Cargo.toml
- CI tests for arg validation; live-API tests are #[ignore]'d

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

codacy-production Bot commented May 20, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds online OpenCage geocoding support to qsv geocode, complementing the existing offline GeoNames/MaxMind-based subcommands. This introduces new CLI surface area, online HTTP integration (with caching and rate limiting), and associated documentation/tests.

Changes:

  • Add geocode opencage / geocode opencagenow subcommands with API key handling, rate limiting, and persistent disk caching.
  • Extend geocode formatting to support OpenCage-specific % formats and dotted-key dynamic templates.
  • Update docs/help and README references; add basic argument-validation tests plus ignored live-API tests.

Reviewed changes

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

Show a summary per file
File Description
src/cmd/geocode.rs Implements OpenCage online geocoding flow, CLI flags, caching, rate limiting, and formatting helpers.
tests/test_geocode.rs Adds CI-safe argument-validation tests and ignored live-API integration tests for OpenCage.
docs/help/geocode.md Documents new OpenCage subcommands and OpenCage-only options.
README.md Updates the command table entry for geocode to mention OpenCage online support.
Cargo.toml Adds governor to the geocode feature set.
.claude/skills/qsv/qsv-geocode.json Extends the geocode skill schema to include new subcommands and OpenCage-related flags.
Comments suppressed due to low confidence (1)

tests/test_geocode.rs:2044

  • This test runs the live OpenCage command twice (assert_success and then read_stdout each invoke cmd.output()), which doubles API usage when running ignored live tests. Prefer capturing cmd.output() once and parsing stdout from that output to avoid extra API calls.
    wrk.assert_success(&mut cmd);

    let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    assert_eq!(got.len(), 4);

Comment thread src/cmd/geocode.rs
Comment thread src/cmd/geocode.rs Outdated
Comment thread tests/test_geocode.rs Outdated
Comment thread README.md Outdated
Comment thread .claude/skills/qsv/qsv-geocode.json
…rify README

- log a warning when remove_expired_entries() fails instead of silently
  discarding the error (Copilot review)
- the geocode_opencage CI tests now capture cmd.output() once and assert on
  both status and stderr, instead of running the command twice (Copilot review)
- README: attribute the 360k records/sec figure to the offline path and note
  that OpenCage online geocoding is sequential and rate-limited (Copilot review)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jqnatividad jqnatividad merged commit b032068 into master May 20, 2026
29 checks passed
@jqnatividad jqnatividad deleted the geocode-opencage-support branch May 20, 2026 14:33
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.

geocode: add OpenCage support

2 participants