Skip to content

Fix #542: add a Couchbase source Kamelet - #3007

Merged
oscerd merged 1 commit into
apache:mainfrom
oscerd:ci-issue-542
Sep 7, 2026
Merged

Fix #542: add a Couchbase source Kamelet#3007
oscerd merged 1 commit into
apache:mainfrom
oscerd:ci-issue-542

Conversation

@oscerd

@oscerd oscerd commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #542.

The catalog shipped couchbase-sink but nothing on the consuming side, even though camel-couchbase supports both. This adds the missing half.

Two polling modes, both exposed

The component's own description is "Query Couchbase databases using SQL (N1QL) queries or MapReduce Views with a poll strategy", and the Kamelet covers both:

  • N1QL (default) — the statement property runs against the bucket on each poll
  • MapReduce view — set useView: true and select it with designDocumentName / viewName

Rather than pick one and hide the other, the description says plainly which properties belong to which mode, since designDocumentName and viewName are inert unless useView is on.

Consistency with the sink

Connection and credential properties mirror couchbase-sink exactly — same names (protocol, couchbaseHostname, couchbasePort, bucket, username, password), same format: password and credentials descriptor on the password, and the same connectionString escape hatch with the same wording. Someone configuring the pair should not have to learn two vocabularies.

The source-only additions are the query options the consumer actually reads: statement, useView, designDocumentName, viewName, fullDocument, limit, skip, descending, and delay for the poll interval. The sink-only startingId / autoStartId are deliberately absent — they configure insert id generation and have no meaning on a consumer.

Verification

script/validator reports no errors, script/generator adds the nav.adoc entry, and mvn clean install passes with tests from the repository root.

Parameter binding checked against the real component with camel run. The Couchbase SDK initialises and starts bootstrapping from the configured host:

Routes startup (total:1 started:1 kamelets:1)
[com.couchbase.core][CoreCreatedEvent] {"connectionString":"couchbase://localhost", ...}
[com.couchbase.node][NodeCreatedEvent] Node created {"managerPort":"8091","remote":"localhost"}

with zero unknown-option or endpoint-resolution errors — it then simply cannot reach a cluster that is not running. A mistyped parameter would have failed before any of that.

No Citrus test: exercising this needs a live Couchbase and the project's Citrus/Testcontainers toolchain has no Couchbase container, so it ships Preview without kamelet.verified=true. Happy to add one in a follow-up if there is an image the project is willing to depend on.

The icon is the existing Couchbase icon reused from couchbase-sink, so the pair renders consistently.


Claude Code on behalf of Andrea Cosentino

The catalog had couchbase-sink but nothing on the consuming side, even
though camel-couchbase supports both. This adds the missing half.

The component polls a bucket in one of two modes and the Kamelet exposes
both: an N1QL statement, which is the default, or a MapReduce view selected
with designDocumentName and viewName when useView is true. Connection and
credential properties mirror couchbase-sink exactly, including the
connectionString escape hatch, so the pair reads the same way.

Marked Preview, no Citrus test: exercising it needs a live Couchbase and
there is no Couchbase container in the project's Citrus toolchain.

Verified with `camel run` against the real component -- the Couchbase SDK
initialises and begins bootstrapping from the configured host, the route
reports "Routes startup (total:1 started:1 kamelets:1)" and there are zero
unknown-option or endpoint-resolution errors; it then simply cannot reach a
cluster that is not there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tz352mt7yzGWLfvYTBo2Dk
@oscerd
oscerd merged commit 4d56764 into apache:main Sep 7, 2026
6 checks passed
oscerd added a commit that referenced this pull request Sep 7, 2026
Follow-up to #3007, which shipped the Kamelet without a test because there
was no Couchbase container in the toolchain. There is one -- it just needs
setting up by hand.

Citrus 5.0.0 has no built-in Couchbase container type, so this uses the
generic container with couchbase/server:community-7.6.2. Three details were
not optional:

- Ports are bound one-to-one. The Couchbase SDK bootstraps from the
  management port and then reconnects using the addresses the cluster
  advertises, so a remapped host port leaves the client unable to reach the
  data service.
- The wait strategy needs a full-line regex. Testcontainers matches log
  wait patterns against the whole line, so "Starting Couchbase Server" never
  matches and the container times out after five minutes.
- initCluster.groovy avoids Groovy GStrings entirely. Citrus resolves
  dollar-brace expressions in these scripts as its own test variables, so a
  GString fails with "Unknown variable".

The script initialises the cluster, creates a bucket, adds a primary index
and seeds one document over plain HTTP, so the test module needs no
Couchbase SDK on its classpath. It polls for the management port itself
because the container logs its startup line well before that port serves
requests.

The statement in application.properties is
"SELECT META().id AS __id, * FROM _default" rather than the more obvious
"SELECT * FROM <bucket>". Both parts matter: CouchbaseConsumer skips any
row without the __id alias, and it runs the query in the bucket scope, so
the keyspace is the collection.

Passes locally in about 35 seconds:

  Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 -- in CouchbaseIT
  SUCCESS (38088ms) couchbase-source-route-test


Claude-Session: https://claude.ai/code/session_01Tz352mt7yzGWLfvYTBo2Dk

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
oscerd added a commit that referenced this pull request Sep 7, 2026
The example shipped in #3007 -- SELECT * FROM `travel-sample` LIMIT 10 --
does not work, and fails in the worst way: the source polls happily and
emits nothing.

Two requirements, both found by running the Kamelet against a live cluster
while writing the integration test in #3008:

CouchbaseConsumer reads row.getString("__id") and skips any row without
that field, logging a warning rather than failing. A query that does not
alias the document id as __id therefore produces no exchanges at all.

The consumer runs the query through scope.query(...), so the keyspace
resolves as <bucket>._default.<what-you-wrote>. Naming the bucket gives
<bucket>._default.<bucket> and fails with "Keyspace not found"; the
collection, normally _default, is what belongs there.

The example now matches what the integration test actually uses, and the
description states both requirements so the next person does not have to
rediscover them from a silent no-op.


Claude-Session: https://claude.ai/code/session_01Tz352mt7yzGWLfvYTBo2Dk

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Create Couchbase Source Kamelet

1 participant