This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new fc0232611226 CAMEL-23218: Add SQL++ (N1QL) query support for Couchbase
consumer
fc0232611226 is described below
commit fc0232611226784db75c75718969e22e86fb8424
Author: Guillaume Nodet <[email protected]>
AuthorDate: Fri Mar 20 10:27:19 2026 +0100
CAMEL-23218: Add SQL++ (N1QL) query support for Couchbase consumer
Add SQL++ query support as the default consumer query mode for
camel-couchbase,
replacing the deprecated MapReduce Views.
Changes:
- Add `statement` option for explicit SQL++ queries
- Add `useView` option (default false) to opt into deprecated View mode
- Auto-generate SQL++ from endpoint options (bucket, collection, limit,
skip,
descending, rangeStartKey, rangeEndKey) when no explicit statement is
given
- Deprecate `designDocumentName` and `viewName` endpoint options
- Add comprehensive documentation with migration guide from Views to SQL++
- Add upgrade guide entry for 4.19
- Add unit tests for SQL++ query generation
- Add integration test (ConsumeSqlQueryIT) covering explicit,
auto-generated,
and raw result query modes
---
.../apache/camel/catalog/components/couchbase.json | 70 +++----
.../couchbase/CouchbaseEndpointConfigurer.java | 9 +
.../couchbase/CouchbaseEndpointUriFactory.java | 4 +-
.../camel/component/couchbase/couchbase.json | 70 +++----
.../src/main/docs/couchbase-component.adoc | 115 +++++++++++-
.../component/couchbase/CouchbaseConsumer.java | 204 +++++++++++++++------
.../component/couchbase/CouchbaseEndpoint.java | 109 ++++++++++-
.../component/couchbase/CouchbaseEndpointTest.java | 76 ++++++++
.../couchbase/integration/ConsumeSqlQueryIT.java | 168 +++++++++++++++++
.../hazelcast/policy/HazelcastRoutePolicyIT.java | 116 ++++++++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_19.adoc | 14 ++
.../component/ComponentsBuilderFactory.java | 5 +-
.../dsl/CouchbaseComponentBuilderFactory.java | 9 +-
.../builder/endpoint/StaticEndpointBuilders.java | 10 +-
.../dsl/CouchbaseEndpointBuilderFactory.java | 81 +++++++-
15 files changed, 912 insertions(+), 148 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
index e22d917b5262..09f621e665fd 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/couchbase.json
@@ -3,7 +3,7 @@
"kind": "component",
"name": "couchbase",
"title": "Couchbase",
- "description": "Query Couchbase Views with a poll strategy and\/or perform
various operations against Couchbase databases.",
+ "description": "Query Couchbase databases using SQL (N1QL) queries or
MapReduce Views with a poll strategy and\/or perform various operations against
Couchbase databases.",
"deprecated": false,
"firstVersion": "2.19.0",
"label": "database",
@@ -49,44 +49,46 @@
"consumerProcessedStrategy": { "index": 7, "kind": "parameter",
"displayName": "Consumer Processed Strategy", "group": "consumer", "label":
"consumer", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "none", "description": "Define the consumer Processed strategy
to use" },
"consumerRetryPause": { "index": 8, "kind": "parameter", "displayName":
"Consumer Retry Pause", "group": "consumer", "label": "consumer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 5000, "description": "Define the
consumer retry pause between different attempts" },
"descending": { "index": 9, "kind": "parameter", "displayName":
"Descending", "group": "consumer", "label": "consumer", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": false, "description": "Define if this
operation is descending or not" },
- "designDocumentName": { "index": 10, "kind": "parameter", "displayName":
"Design Document Name", "group": "consumer", "label": "consumer", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "beer", "description":
"The design document name to use" },
+ "designDocumentName": { "index": 10, "kind": "parameter", "displayName":
"Design Document Name", "group": "consumer", "label": "consumer", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": true,
"autowired": false, "secret": false, "defaultValue": "beer", "description":
"The design document name to use. Deprecated: use the statement option with SQL
queries instead." },
"fullDocument": { "index": 11, "kind": "parameter", "displayName": "Full
Document", "group": "consumer", "label": "consumer", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If true consumer will
return complete document instead data defined in view" },
"limit": { "index": 12, "kind": "parameter", "displayName": "Limit",
"group": "consumer", "label": "consumer", "required": false, "type": "integer",
"javaType": "int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": -1, "description": "The output limit to use" },
"rangeEndKey": { "index": 13, "kind": "parameter", "displayName": "Range
End Key", "group": "consumer", "label": "consumer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "description": "Define a range for the end key" },
"rangeStartKey": { "index": 14, "kind": "parameter", "displayName": "Range
Start Key", "group": "consumer", "label": "consumer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "Define a range for the
start key" },
"sendEmptyMessageWhenIdle": { "index": 15, "kind": "parameter",
"displayName": "Send Empty Message When Idle", "group": "consumer", "label":
"consumer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "If the polling consumer did not poll any files, you can
enable this option to send an empty message (no body) instead." },
"skip": { "index": 16, "kind": "parameter", "displayName": "Skip",
"group": "consumer", "label": "consumer", "required": false, "type": "integer",
"javaType": "int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": -1, "description": "Define the skip to use" },
- "viewName": { "index": 17, "kind": "parameter", "displayName": "View
Name", "group": "consumer", "label": "consumer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "brewery_beers", "description": "The
view name to use" },
- "bridgeErrorHandler": { "index": 18, "kind": "parameter", "displayName":
"Bridge Error Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Allows for bridging the consumer to the
Camel routing Error Handler, which mean any exceptions (if possible) occurred
while the Camel consumer is trying to pickup incoming [...]
- "exceptionHandler": { "index": 19, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By de [...]
- "exchangePattern": { "index": 20, "kind": "parameter", "displayName":
"Exchange Pattern", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "enum", "javaType":
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ],
"deprecated": false, "autowired": false, "secret": false, "description": "Sets
the exchange pattern when the consumer creates an exchange." },
- "pollStrategy": { "index": 21, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
- "autoStartIdForInserts": { "index": 22, "kind": "parameter",
"displayName": "Auto Start Id For Inserts", "group": "producer", "label":
"producer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "Define if we want an autostart Id when we are doing an
insert operation" },
- "operation": { "index": 23, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "CCB_PUT", "description":
"The operation to do" },
- "persistTo": { "index": 24, "kind": "parameter", "displayName": "Persist
To", "group": "producer", "label": "producer", "required": false, "type":
"integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to persist the data"
},
- "producerRetryAttempts": { "index": 25, "kind": "parameter",
"displayName": "Producer Retry Attempts", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 2,
"description": "Define the number of retry attempts" },
- "producerRetryPause": { "index": 26, "kind": "parameter", "displayName":
"Producer Retry Pause", "group": "producer", "label": "producer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 5000, "description": "Define the
producer retry pause between different attempts" },
- "replicateTo": { "index": 27, "kind": "parameter", "displayName":
"Replicate To", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to replicate the
data" },
- "startingIdForInsertsFrom": { "index": 28, "kind": "parameter",
"displayName": "Starting Id For Inserts From", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "long",
"deprecated": false, "autowired": false, "secret": false, "description":
"Define the starting Id where we are doing an insert operation" },
- "lazyStartProducer": { "index": 29, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
- "additionalHosts": { "index": 30, "kind": "parameter", "displayName":
"Additional Hosts", "group": "advanced", "label": "advanced", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The additional hosts" },
- "connectTimeout": { "index": 31, "kind": "parameter", "displayName":
"Connect Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "duration", "javaType": "long", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "30000", "description": "Define the
timeoutconnect in milliseconds" },
- "queryTimeout": { "index": 32, "kind": "parameter", "displayName": "Query
Timeout", "group": "advanced", "label": "advanced", "required": false, "type":
"duration", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "2500", "description": "Define the operation
timeout in milliseconds" },
- "backoffErrorThreshold": { "index": 33, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
- "backoffIdleThreshold": { "index": 34, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
- "backoffMultiplier": { "index": 35, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
- "delay": { "index": 36, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
- "greedy": { "index": 37, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
- "initialDelay": { "index": 38, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
- "repeatCount": { "index": 39, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
- "runLoggingLevel": { "index": 40, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
- "scheduledExecutorService": { "index": 41, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
- "scheduler": { "index": 42, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
- "schedulerProperties": { "index": 43, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
- "startScheduler": { "index": 44, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
- "timeUnit": { "index": 45, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
- "useFixedDelay": { "index": 46, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." },
- "password": { "index": 47, "kind": "parameter", "displayName": "Password",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The password to use" },
- "username": { "index": 48, "kind": "parameter", "displayName": "Username",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The username to use" }
+ "statement": { "index": 17, "kind": "parameter", "displayName":
"Statement", "group": "consumer", "label": "consumer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "A SQL (N1QL) query
statement for consuming documents. When set, the consumer uses SQL queries
instead of MapReduce views. The query should select META().id AS __id to
identify documents. Example: SELECT META().id AS __id, FROM [...]
+ "useView": { "index": 18, "kind": "parameter", "displayName": "Use View",
"group": "consumer", "label": "consumer", "required": false, "type": "boolean",
"javaType": "boolean", "deprecated": false, "autowired": false, "secret":
false, "defaultValue": false, "description": "If true, use the deprecated
MapReduce Views to query documents via designDocumentName and viewName. If
false (default), use SQL queries instead." },
+ "viewName": { "index": 19, "kind": "parameter", "displayName": "View
Name", "group": "consumer", "label": "consumer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": true, "autowired":
false, "secret": false, "defaultValue": "brewery_beers", "description": "The
view name to use. Deprecated: use the statement option with SQL queries
instead." },
+ "bridgeErrorHandler": { "index": 20, "kind": "parameter", "displayName":
"Bridge Error Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Allows for bridging the consumer to the
Camel routing Error Handler, which mean any exceptions (if possible) occurred
while the Camel consumer is trying to pickup incoming [...]
+ "exceptionHandler": { "index": 21, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By de [...]
+ "exchangePattern": { "index": 22, "kind": "parameter", "displayName":
"Exchange Pattern", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "enum", "javaType":
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ],
"deprecated": false, "autowired": false, "secret": false, "description": "Sets
the exchange pattern when the consumer creates an exchange." },
+ "pollStrategy": { "index": 23, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
+ "autoStartIdForInserts": { "index": 24, "kind": "parameter",
"displayName": "Auto Start Id For Inserts", "group": "producer", "label":
"producer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "Define if we want an autostart Id when we are doing an
insert operation" },
+ "operation": { "index": 25, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "CCB_PUT", "description":
"The operation to do" },
+ "persistTo": { "index": 26, "kind": "parameter", "displayName": "Persist
To", "group": "producer", "label": "producer", "required": false, "type":
"integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to persist the data"
},
+ "producerRetryAttempts": { "index": 27, "kind": "parameter",
"displayName": "Producer Retry Attempts", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 2,
"description": "Define the number of retry attempts" },
+ "producerRetryPause": { "index": 28, "kind": "parameter", "displayName":
"Producer Retry Pause", "group": "producer", "label": "producer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 5000, "description": "Define the
producer retry pause between different attempts" },
+ "replicateTo": { "index": 29, "kind": "parameter", "displayName":
"Replicate To", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to replicate the
data" },
+ "startingIdForInsertsFrom": { "index": 30, "kind": "parameter",
"displayName": "Starting Id For Inserts From", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "long",
"deprecated": false, "autowired": false, "secret": false, "description":
"Define the starting Id where we are doing an insert operation" },
+ "lazyStartProducer": { "index": 31, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "additionalHosts": { "index": 32, "kind": "parameter", "displayName":
"Additional Hosts", "group": "advanced", "label": "advanced", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The additional hosts" },
+ "connectTimeout": { "index": 33, "kind": "parameter", "displayName":
"Connect Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "duration", "javaType": "long", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "30000", "description": "Define the
timeoutconnect in milliseconds" },
+ "queryTimeout": { "index": 34, "kind": "parameter", "displayName": "Query
Timeout", "group": "advanced", "label": "advanced", "required": false, "type":
"duration", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "2500", "description": "Define the operation
timeout in milliseconds" },
+ "backoffErrorThreshold": { "index": 35, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
+ "backoffIdleThreshold": { "index": 36, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
+ "backoffMultiplier": { "index": 37, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
+ "delay": { "index": 38, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
+ "greedy": { "index": 39, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
+ "initialDelay": { "index": 40, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
+ "repeatCount": { "index": 41, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
+ "runLoggingLevel": { "index": 42, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
+ "scheduledExecutorService": { "index": 43, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
+ "scheduler": { "index": 44, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
+ "schedulerProperties": { "index": 45, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
+ "startScheduler": { "index": 46, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
+ "timeUnit": { "index": 47, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
+ "useFixedDelay": { "index": 48, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." },
+ "password": { "index": 49, "kind": "parameter", "displayName": "Password",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The password to use" },
+ "username": { "index": 50, "kind": "parameter", "displayName": "Username",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The username to use" }
}
}
diff --git
a/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointConfigurer.java
b/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointConfigurer.java
index 55b25658ef3e..193f721fa385 100644
---
a/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointConfigurer.java
+++
b/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointConfigurer.java
@@ -95,10 +95,13 @@ public class CouchbaseEndpointConfigurer extends
PropertyConfigurerSupport imple
case "startScheduler": target.setStartScheduler(property(camelContext,
boolean.class, value)); return true;
case "startingidforinsertsfrom":
case "startingIdForInsertsFrom":
target.setStartingIdForInsertsFrom(property(camelContext, long.class, value));
return true;
+ case "statement": target.setStatement(property(camelContext,
java.lang.String.class, value)); return true;
case "timeunit":
case "timeUnit": target.setTimeUnit(property(camelContext,
java.util.concurrent.TimeUnit.class, value)); return true;
case "usefixeddelay":
case "useFixedDelay": target.setUseFixedDelay(property(camelContext,
boolean.class, value)); return true;
+ case "useview":
+ case "useView": target.setUseView(property(camelContext,
boolean.class, value)); return true;
case "username": target.setUsername(property(camelContext,
java.lang.String.class, value)); return true;
case "viewname":
case "viewName": target.setViewName(property(camelContext,
java.lang.String.class, value)); return true;
@@ -181,10 +184,13 @@ public class CouchbaseEndpointConfigurer extends
PropertyConfigurerSupport imple
case "startScheduler": return boolean.class;
case "startingidforinsertsfrom":
case "startingIdForInsertsFrom": return long.class;
+ case "statement": return java.lang.String.class;
case "timeunit":
case "timeUnit": return java.util.concurrent.TimeUnit.class;
case "usefixeddelay":
case "useFixedDelay": return boolean.class;
+ case "useview":
+ case "useView": return boolean.class;
case "username": return java.lang.String.class;
case "viewname":
case "viewName": return java.lang.String.class;
@@ -268,10 +274,13 @@ public class CouchbaseEndpointConfigurer extends
PropertyConfigurerSupport imple
case "startScheduler": return target.isStartScheduler();
case "startingidforinsertsfrom":
case "startingIdForInsertsFrom": return
target.getStartingIdForInsertsFrom();
+ case "statement": return target.getStatement();
case "timeunit":
case "timeUnit": return target.getTimeUnit();
case "usefixeddelay":
case "useFixedDelay": return target.isUseFixedDelay();
+ case "useview":
+ case "useView": return target.isUseView();
case "username": return target.getUsername();
case "viewname":
case "viewName": return target.getViewName();
diff --git
a/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointUriFactory.java
b/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointUriFactory.java
index b3026fbef4bd..a6fd42ec6e89 100644
---
a/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointUriFactory.java
+++
b/components/camel-couchbase/src/generated/java/org/apache/camel/component/couchbase/CouchbaseEndpointUriFactory.java
@@ -23,7 +23,7 @@ public class CouchbaseEndpointUriFactory extends
org.apache.camel.support.compon
private static final Set<String> SECRET_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(49);
+ Set<String> props = new HashSet<>(51);
props.add("additionalHosts");
props.add("autoStartIdForInserts");
props.add("backoffErrorThreshold");
@@ -69,8 +69,10 @@ public class CouchbaseEndpointUriFactory extends
org.apache.camel.support.compon
props.add("skip");
props.add("startScheduler");
props.add("startingIdForInsertsFrom");
+ props.add("statement");
props.add("timeUnit");
props.add("useFixedDelay");
+ props.add("useView");
props.add("username");
props.add("viewName");
PROPERTY_NAMES = Collections.unmodifiableSet(props);
diff --git
a/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
b/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
index e22d917b5262..09f621e665fd 100644
---
a/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
+++
b/components/camel-couchbase/src/generated/resources/META-INF/org/apache/camel/component/couchbase/couchbase.json
@@ -3,7 +3,7 @@
"kind": "component",
"name": "couchbase",
"title": "Couchbase",
- "description": "Query Couchbase Views with a poll strategy and\/or perform
various operations against Couchbase databases.",
+ "description": "Query Couchbase databases using SQL (N1QL) queries or
MapReduce Views with a poll strategy and\/or perform various operations against
Couchbase databases.",
"deprecated": false,
"firstVersion": "2.19.0",
"label": "database",
@@ -49,44 +49,46 @@
"consumerProcessedStrategy": { "index": 7, "kind": "parameter",
"displayName": "Consumer Processed Strategy", "group": "consumer", "label":
"consumer", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "none", "description": "Define the consumer Processed strategy
to use" },
"consumerRetryPause": { "index": 8, "kind": "parameter", "displayName":
"Consumer Retry Pause", "group": "consumer", "label": "consumer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 5000, "description": "Define the
consumer retry pause between different attempts" },
"descending": { "index": 9, "kind": "parameter", "displayName":
"Descending", "group": "consumer", "label": "consumer", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": false, "description": "Define if this
operation is descending or not" },
- "designDocumentName": { "index": 10, "kind": "parameter", "displayName":
"Design Document Name", "group": "consumer", "label": "consumer", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "beer", "description":
"The design document name to use" },
+ "designDocumentName": { "index": 10, "kind": "parameter", "displayName":
"Design Document Name", "group": "consumer", "label": "consumer", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": true,
"autowired": false, "secret": false, "defaultValue": "beer", "description":
"The design document name to use. Deprecated: use the statement option with SQL
queries instead." },
"fullDocument": { "index": 11, "kind": "parameter", "displayName": "Full
Document", "group": "consumer", "label": "consumer", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If true consumer will
return complete document instead data defined in view" },
"limit": { "index": 12, "kind": "parameter", "displayName": "Limit",
"group": "consumer", "label": "consumer", "required": false, "type": "integer",
"javaType": "int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": -1, "description": "The output limit to use" },
"rangeEndKey": { "index": 13, "kind": "parameter", "displayName": "Range
End Key", "group": "consumer", "label": "consumer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "description": "Define a range for the end key" },
"rangeStartKey": { "index": 14, "kind": "parameter", "displayName": "Range
Start Key", "group": "consumer", "label": "consumer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "Define a range for the
start key" },
"sendEmptyMessageWhenIdle": { "index": 15, "kind": "parameter",
"displayName": "Send Empty Message When Idle", "group": "consumer", "label":
"consumer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "If the polling consumer did not poll any files, you can
enable this option to send an empty message (no body) instead." },
"skip": { "index": 16, "kind": "parameter", "displayName": "Skip",
"group": "consumer", "label": "consumer", "required": false, "type": "integer",
"javaType": "int", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": -1, "description": "Define the skip to use" },
- "viewName": { "index": 17, "kind": "parameter", "displayName": "View
Name", "group": "consumer", "label": "consumer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "brewery_beers", "description": "The
view name to use" },
- "bridgeErrorHandler": { "index": 18, "kind": "parameter", "displayName":
"Bridge Error Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Allows for bridging the consumer to the
Camel routing Error Handler, which mean any exceptions (if possible) occurred
while the Camel consumer is trying to pickup incoming [...]
- "exceptionHandler": { "index": 19, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By de [...]
- "exchangePattern": { "index": 20, "kind": "parameter", "displayName":
"Exchange Pattern", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "enum", "javaType":
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ],
"deprecated": false, "autowired": false, "secret": false, "description": "Sets
the exchange pattern when the consumer creates an exchange." },
- "pollStrategy": { "index": 21, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
- "autoStartIdForInserts": { "index": 22, "kind": "parameter",
"displayName": "Auto Start Id For Inserts", "group": "producer", "label":
"producer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "Define if we want an autostart Id when we are doing an
insert operation" },
- "operation": { "index": 23, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "CCB_PUT", "description":
"The operation to do" },
- "persistTo": { "index": 24, "kind": "parameter", "displayName": "Persist
To", "group": "producer", "label": "producer", "required": false, "type":
"integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to persist the data"
},
- "producerRetryAttempts": { "index": 25, "kind": "parameter",
"displayName": "Producer Retry Attempts", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 2,
"description": "Define the number of retry attempts" },
- "producerRetryPause": { "index": 26, "kind": "parameter", "displayName":
"Producer Retry Pause", "group": "producer", "label": "producer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 5000, "description": "Define the
producer retry pause between different attempts" },
- "replicateTo": { "index": 27, "kind": "parameter", "displayName":
"Replicate To", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to replicate the
data" },
- "startingIdForInsertsFrom": { "index": 28, "kind": "parameter",
"displayName": "Starting Id For Inserts From", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "long",
"deprecated": false, "autowired": false, "secret": false, "description":
"Define the starting Id where we are doing an insert operation" },
- "lazyStartProducer": { "index": 29, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
- "additionalHosts": { "index": 30, "kind": "parameter", "displayName":
"Additional Hosts", "group": "advanced", "label": "advanced", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The additional hosts" },
- "connectTimeout": { "index": 31, "kind": "parameter", "displayName":
"Connect Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "duration", "javaType": "long", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "30000", "description": "Define the
timeoutconnect in milliseconds" },
- "queryTimeout": { "index": 32, "kind": "parameter", "displayName": "Query
Timeout", "group": "advanced", "label": "advanced", "required": false, "type":
"duration", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "2500", "description": "Define the operation
timeout in milliseconds" },
- "backoffErrorThreshold": { "index": 33, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
- "backoffIdleThreshold": { "index": 34, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
- "backoffMultiplier": { "index": 35, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
- "delay": { "index": 36, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
- "greedy": { "index": 37, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
- "initialDelay": { "index": 38, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
- "repeatCount": { "index": 39, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
- "runLoggingLevel": { "index": 40, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
- "scheduledExecutorService": { "index": 41, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
- "scheduler": { "index": 42, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
- "schedulerProperties": { "index": 43, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
- "startScheduler": { "index": 44, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
- "timeUnit": { "index": 45, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
- "useFixedDelay": { "index": 46, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." },
- "password": { "index": 47, "kind": "parameter", "displayName": "Password",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The password to use" },
- "username": { "index": 48, "kind": "parameter", "displayName": "Username",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The username to use" }
+ "statement": { "index": 17, "kind": "parameter", "displayName":
"Statement", "group": "consumer", "label": "consumer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "A SQL (N1QL) query
statement for consuming documents. When set, the consumer uses SQL queries
instead of MapReduce views. The query should select META().id AS __id to
identify documents. Example: SELECT META().id AS __id, FROM [...]
+ "useView": { "index": 18, "kind": "parameter", "displayName": "Use View",
"group": "consumer", "label": "consumer", "required": false, "type": "boolean",
"javaType": "boolean", "deprecated": false, "autowired": false, "secret":
false, "defaultValue": false, "description": "If true, use the deprecated
MapReduce Views to query documents via designDocumentName and viewName. If
false (default), use SQL queries instead." },
+ "viewName": { "index": 19, "kind": "parameter", "displayName": "View
Name", "group": "consumer", "label": "consumer", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": true, "autowired":
false, "secret": false, "defaultValue": "brewery_beers", "description": "The
view name to use. Deprecated: use the statement option with SQL queries
instead." },
+ "bridgeErrorHandler": { "index": 20, "kind": "parameter", "displayName":
"Bridge Error Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Allows for bridging the consumer to the
Camel routing Error Handler, which mean any exceptions (if possible) occurred
while the Camel consumer is trying to pickup incoming [...]
+ "exceptionHandler": { "index": 21, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By de [...]
+ "exchangePattern": { "index": 22, "kind": "parameter", "displayName":
"Exchange Pattern", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "enum", "javaType":
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ],
"deprecated": false, "autowired": false, "secret": false, "description": "Sets
the exchange pattern when the consumer creates an exchange." },
+ "pollStrategy": { "index": 23, "kind": "parameter", "displayName": "Poll
Strategy", "group": "consumer (advanced)", "label": "consumer,advanced",
"required": false, "type": "object", "javaType":
"org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false,
"autowired": false, "secret": false, "description": "A pluggable
org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your
custom implementation to control error handling usually occurred during the po
[...]
+ "autoStartIdForInserts": { "index": 24, "kind": "parameter",
"displayName": "Auto Start Id For Inserts", "group": "producer", "label":
"producer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "Define if we want an autostart Id when we are doing an
insert operation" },
+ "operation": { "index": 25, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "CCB_PUT", "description":
"The operation to do" },
+ "persistTo": { "index": 26, "kind": "parameter", "displayName": "Persist
To", "group": "producer", "label": "producer", "required": false, "type":
"integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to persist the data"
},
+ "producerRetryAttempts": { "index": 27, "kind": "parameter",
"displayName": "Producer Retry Attempts", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 2,
"description": "Define the number of retry attempts" },
+ "producerRetryPause": { "index": 28, "kind": "parameter", "displayName":
"Producer Retry Pause", "group": "producer", "label": "producer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 5000, "description": "Define the
producer retry pause between different attempts" },
+ "replicateTo": { "index": 29, "kind": "parameter", "displayName":
"Replicate To", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Where to replicate the
data" },
+ "startingIdForInsertsFrom": { "index": 30, "kind": "parameter",
"displayName": "Starting Id For Inserts From", "group": "producer", "label":
"producer", "required": false, "type": "integer", "javaType": "long",
"deprecated": false, "autowired": false, "secret": false, "description":
"Define the starting Id where we are doing an insert operation" },
+ "lazyStartProducer": { "index": 31, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "additionalHosts": { "index": 32, "kind": "parameter", "displayName":
"Additional Hosts", "group": "advanced", "label": "advanced", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "description": "The additional hosts" },
+ "connectTimeout": { "index": 33, "kind": "parameter", "displayName":
"Connect Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "duration", "javaType": "long", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "30000", "description": "Define the
timeoutconnect in milliseconds" },
+ "queryTimeout": { "index": 34, "kind": "parameter", "displayName": "Query
Timeout", "group": "advanced", "label": "advanced", "required": false, "type":
"duration", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "2500", "description": "Define the operation
timeout in milliseconds" },
+ "backoffErrorThreshold": { "index": 35, "kind": "parameter",
"displayName": "Backoff Error Threshold", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "description": "The
number of subsequent error polls (failed due some error) that should happen
before the backoffMultipler should kick-in." },
+ "backoffIdleThreshold": { "index": 36, "kind": "parameter", "displayName":
"Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "The number of subsequent
idle polls that should happen before the backoffMultipler should kick-in." },
+ "backoffMultiplier": { "index": 37, "kind": "parameter", "displayName":
"Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "int", "deprecated": false,
"autowired": false, "secret": false, "description": "To let the scheduled
polling consumer backoff if there has been a number of subsequent idles\/errors
in a row. The multiplier is then the number of polls that will be skipped
before the next actual attempt is h [...]
+ "delay": { "index": 38, "kind": "parameter", "displayName": "Delay",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 500, "description": "Milliseconds before the
next poll." },
+ "greedy": { "index": 39, "kind": "parameter", "displayName": "Greedy",
"group": "scheduler", "label": "consumer,scheduler", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If greedy is enabled,
then the ScheduledPollConsumer will run immediately again, if the previous run
polled 1 or more messages." },
+ "initialDelay": { "index": 40, "kind": "parameter", "displayName":
"Initial Delay", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": 1000, "description":
"Milliseconds before the first poll starts." },
+ "repeatCount": { "index": 41, "kind": "parameter", "displayName": "Repeat
Count", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 0, "description": "Specifies a maximum limit
of number of fires. So if you set it to 1, the scheduler will only fire once.
If you set it to 5, it will only fire five times. A value of zero or negative
means fire forever." },
+ "runLoggingLevel": { "index": 42, "kind": "parameter", "displayName": "Run
Logging Level", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel",
"enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "TRACE",
"description": "The consumer logs a start\/complete log line when it polls.
This option allows you to configure the log [...]
+ "scheduledExecutorService": { "index": 43, "kind": "parameter",
"displayName": "Scheduled Executor Service", "group": "scheduler", "label":
"consumer,scheduler", "required": false, "type": "object", "javaType":
"java.util.concurrent.ScheduledExecutorService", "deprecated": false,
"autowired": false, "secret": false, "description": "Allows for configuring a
custom\/shared thread pool to use for the consumer. By default each consumer
has its own single threaded thread pool." },
+ "scheduler": { "index": 44, "kind": "parameter", "displayName":
"Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "object", "javaType": "java.lang.Object", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "none", "description": "To
use a cron scheduler from either camel-spring or camel-quartz component. Use
value spring or quartz for built in scheduler" },
+ "schedulerProperties": { "index": 45, "kind": "parameter", "displayName":
"Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "object", "javaType":
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": "scheduler.",
"multiValue": true, "deprecated": false, "autowired": false, "secret": false,
"description": "To configure additional properties when using a custom
scheduler or any of the Quartz, Spring based scheduler. This i [...]
+ "startScheduler": { "index": 46, "kind": "parameter", "displayName":
"Start Scheduler", "group": "scheduler", "label": "consumer,scheduler",
"required": false, "type": "boolean", "javaType": "boolean", "deprecated":
false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Whether the scheduler should be auto started." },
+ "timeUnit": { "index": 47, "kind": "parameter", "displayName": "Time
Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false,
"type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [
"NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS",
"DAYS" ], "deprecated": false, "autowired": false, "secret": false,
"defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and
delay options." },
+ "useFixedDelay": { "index": 48, "kind": "parameter", "displayName": "Use
Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in
JDK for details." },
+ "password": { "index": 49, "kind": "parameter", "displayName": "Password",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The password to use" },
+ "username": { "index": 50, "kind": "parameter", "displayName": "Username",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "description": "The username to use" }
}
}
diff --git a/components/camel-couchbase/src/main/docs/couchbase-component.adoc
b/components/camel-couchbase/src/main/docs/couchbase-component.adoc
index 3e71f248d233..5551f7bf43a1 100644
--- a/components/camel-couchbase/src/main/docs/couchbase-component.adoc
+++ b/components/camel-couchbase/src/main/docs/couchbase-component.adoc
@@ -2,7 +2,7 @@
:doctitle: Couchbase
:shortname: couchbase
:artifactid: camel-couchbase
-:description: Query Couchbase Views with a poll strategy and/or perform
various operations against Couchbase databases.
+:description: Query Couchbase databases using SQL (N1QL) queries or MapReduce
Views with a poll strategy and/or perform various operations against Couchbase
databases.
:since: 2.19
:supportlevel: Stable
:tabs-sync-option:
@@ -44,6 +44,119 @@ include::partial$component-endpoint-options.adoc[]
include::partial$component-endpoint-headers.adoc[]
// component options: END
+== Consuming documents
+
+The consumer supports two query modes for polling documents from Couchbase:
+
+=== SQL++ queries (recommended, default)
+
+Since Couchbase Server 7.0, the recommended way to query documents is using
SQL++ (formerly N1QL).
+MapReduce Views are deprecated since Couchbase 7.0 and do not work with the
Magma storage backend
+(default since Couchbase 8.0).
+
+By default, the consumer uses SQL++ queries. You can either provide an
explicit `statement` or
+let the consumer auto-generate one from the endpoint options.
+
+==== Auto-generated queries
+
+The simplest way to consume documents is to just use the existing endpoint
options. The consumer
+auto-generates a SQL++ query from `bucket`, `collection`, `limit`, `skip`,
`descending`,
+`rangeStartKey`, and `rangeEndKey`:
+
+[source,java]
+----
+// Consumes up to 10 documents in descending order
+from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass&limit=10&descending=true")
+ .to("direct:result");
+----
+
+This generates: `SELECT META().id AS \__id, * FROM \`myBucket\` ORDER BY
META().id DESC LIMIT 10`
+
+==== Explicit SQL++ statements
+
+For complex queries (filters, joins, aggregations), set the `statement` option
directly:
+
+[source,java]
+----
+from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
+ + "&statement=SELECT META().id AS __id, * FROM `myCollection` WHERE type =
'order' LIMIT 100")
+ .to("direct:result");
+----
+
+The query must include `META().id AS \__id` in the SELECT clause so the
consumer can identify each document.
+
+When `fullDocument` is `true` (the default), the consumer fetches the complete
document from the KV store using
+the document ID. When `false`, the query result row is used directly as the
message body.
+
+NOTE: SQL++ queries require a primary index or appropriate secondary index on
the bucket/collection.
+Create one with: `CREATE PRIMARY INDEX ON \`myBucket\`` or via the Couchbase
SDK.
+
+=== MapReduce Views (deprecated)
+
+The consumer can also poll documents using MapReduce Views by setting
`useView=true` with the
+`designDocumentName` and `viewName` endpoint options. This mode is deprecated
and will be removed
+in a future release.
+
+[source,java]
+----
+from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
+ + "&useView=true&designDocumentName=myDoc&viewName=myView&limit=10")
+ .to("direct:result");
+----
+
+=== Migrating from Views to SQL++
+
+To migrate from MapReduce Views to SQL++, simply remove `designDocumentName`
and `viewName` from
+your endpoint URI. The `limit`, `skip`, `descending`, `rangeStartKey`, and
`rangeEndKey` options
+are automatically translated to SQL++ clauses:
+
+[cols="1,1",options="header"]
+|===
+| View option | SQL++ equivalent
+
+| `designDocumentName` + `viewName`
+| Removed (or replaced by `statement` for custom queries)
+
+| `limit=10`
+| `LIMIT 10`
+
+| `skip=5`
+| `OFFSET 5`
+
+| `descending=true`
+| `ORDER BY META().id DESC`
+
+| `rangeStartKey=A` / `rangeEndKey=Z`
+| `WHERE META().id >= 'A' AND META().id \<= 'Z'`
+
+| `fullDocument=true`
+| Works the same way in both modes
+|===
+
+For example, a view-based consumer:
+
+[source,java]
+----
+from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
+ +
"&useView=true&designDocumentName=myDoc&viewName=myView&limit=10&descending=true")
+----
+
+Can be migrated by simply removing the view-specific options:
+
+[source,java]
+----
+from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
+ + "&limit=10&descending=true")
+----
+
+Or with an explicit SQL++ statement for more control:
+
+[source,java]
+----
+from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass"
+ + "&statement=SELECT META().id AS __id, * FROM `myBucket` ORDER BY
META().id DESC LIMIT 10")
+----
+
== Couchbase SDK compatibility
Using collections and scopes is supported only for Couchbase Server 7.0 and
later.
diff --git
a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
index 1499f16e873b..d7068391d38a 100644
---
a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
+++
b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
@@ -24,6 +24,10 @@ import java.util.concurrent.locks.ReentrantLock;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Collection;
import com.couchbase.client.java.Scope;
+import com.couchbase.client.java.json.JsonObject;
+import com.couchbase.client.java.query.QueryOptions;
+import com.couchbase.client.java.query.QueryResult;
+import com.couchbase.client.java.query.QueryScanConsistency;
import com.couchbase.client.java.view.ViewOptions;
import com.couchbase.client.java.view.ViewOrdering;
import com.couchbase.client.java.view.ViewResult;
@@ -48,11 +52,16 @@ public class CouchbaseConsumer extends
ScheduledBatchPollingConsumer implements
private static final Logger LOG =
LoggerFactory.getLogger(CouchbaseConsumer.class);
+ static final String SQL_DOCUMENT_ID_ALIAS = "__id";
+
private final Lock lock = new ReentrantLock();
private final CouchbaseEndpoint endpoint;
private Bucket bucket;
+ private Scope scope;
private Collection collection;
private ViewOptions viewOptions;
+ private boolean useSqlQuery;
+ private String sqlStatement;
private ResumeStrategy resumeStrategy;
@@ -66,11 +75,10 @@ public class CouchbaseConsumer extends
ScheduledBatchPollingConsumer implements
protected void doInit() throws Exception {
super.doInit();
- Scope scope;
if (endpoint.getScope() != null) {
- scope = bucket.scope(endpoint.getScope());
+ this.scope = bucket.scope(endpoint.getScope());
} else {
- scope = bucket.defaultScope();
+ this.scope = bucket.defaultScope();
}
if (endpoint.getCollection() != null) {
@@ -79,6 +87,25 @@ public class CouchbaseConsumer extends
ScheduledBatchPollingConsumer implements
this.collection = bucket.defaultCollection();
}
+ // Determine query mode
+ if (endpoint.getStatement() != null) {
+ // Explicit SQL++ statement provided
+ useSqlQuery = true;
+ sqlStatement = endpoint.getStatement();
+ } else if (!endpoint.isUseView()) {
+ // Auto-generate SQL++ from endpoint options
+ useSqlQuery = true;
+ sqlStatement = endpoint.buildSqlQuery();
+ LOG.info("Auto-generated SQL++ query: {}", sqlStatement);
+ } else {
+ // Use deprecated MapReduce views
+ useSqlQuery = false;
+ initViewOptions();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private void initViewOptions() {
this.viewOptions = ViewOptions.viewOptions();
int limit = endpoint.getLimit();
if (limit > 0) {
@@ -120,66 +147,137 @@ public class CouchbaseConsumer extends
ScheduledBatchPollingConsumer implements
protected int poll() throws Exception {
lock.lock();
try {
- ViewResult result =
bucket.viewQuery(endpoint.getDesignDocumentName(), endpoint.getViewName(),
this.viewOptions);
+ if (useSqlQuery) {
+ return pollWithSqlQuery();
+ } else {
+ return pollWithView();
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
- // okay we have some response from CouchBase so lets mark the
consumer as ready
- forceConsumerAsReady();
+ private int pollWithSqlQuery() throws Exception {
+ QueryOptions queryOptions = QueryOptions.queryOptions()
+ .scanConsistency(QueryScanConsistency.REQUEST_PLUS);
- if (LOG.isTraceEnabled()) {
- LOG.trace("ViewResponse: {}", result);
+ QueryResult result = scope.query(sqlStatement, queryOptions);
+
+ forceConsumerAsReady();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("QueryResult: {}", result);
+ }
+
+ String consumerProcessedStrategy =
endpoint.getConsumerProcessedStrategy();
+ Queue<Object> exchanges = new ArrayDeque<>();
+
+ for (JsonObject row : result.rowsAsObject()) {
+ String id = row.getString(SQL_DOCUMENT_ID_ALIAS);
+ if (id == null) {
+ LOG.warn("Row does not contain '{}' field. "
+ + "Ensure your SQL++ query includes META().id AS {}
in the SELECT clause. Skipping row.",
+ SQL_DOCUMENT_ID_ALIAS, SQL_DOCUMENT_ID_ALIAS);
+ continue;
}
- String consumerProcessedStrategy =
endpoint.getConsumerProcessedStrategy();
-
- Queue<Object> exchanges = new ArrayDeque<>();
- for (ViewRow row : result.rows()) {
- Object doc;
- String id = row.id().get();
- if (endpoint.isFullDocument()) {
- doc = CouchbaseCollectionOperation.getDocument(collection,
id, endpoint.getQueryTimeout(),
- endpoint.getConsumerRetryPause());
- } else {
- doc = row.valueAs(Object.class);
- }
+ Object doc;
+ if (endpoint.isFullDocument()) {
+ doc = CouchbaseCollectionOperation.getDocument(collection, id,
endpoint.getQueryTimeout(),
+ endpoint.getConsumerRetryPause());
+ } else {
+ doc = row.toString();
+ }
- // Use String.class instead of the shaded JsonNode class to
avoid conflicts
- // when Jackson is on the classpath (CAMEL-22090). The
Couchbase SDK's
- // auto-detection of non-shaded Jackson would otherwise cause
deserialization
- // failures when trying to deserialize into the shaded
JsonNode class.
- String key = row.keyAs(String.class).orElse(null);
- String designDocumentName = endpoint.getDesignDocumentName();
- String viewName = endpoint.getViewName();
-
- Exchange exchange = createExchange(true);
- exchange.getIn().setBody(doc);
- exchange.getIn().setHeader(HEADER_ID, id);
- exchange.getIn().setHeader(HEADER_KEY, key);
- exchange.getIn().setHeader(HEADER_DESIGN_DOCUMENT_NAME,
designDocumentName);
- exchange.getIn().setHeader(HEADER_VIEWNAME, viewName);
-
- if ("delete".equalsIgnoreCase(consumerProcessedStrategy)) {
- if (LOG.isTraceEnabled()) {
- LOG.trace("Deleting doc with ID {}", id);
- }
- CouchbaseCollectionOperation.removeDocument(collection,
id, endpoint.getWriteQueryTimeout(),
- endpoint.getConsumerRetryPause());
- } else if
("filter".equalsIgnoreCase(consumerProcessedStrategy)) {
- if (LOG.isTraceEnabled()) {
- LOG.trace("Filtering out ID {}", id);
- }
- // add filter for already processed docs
- } else {
- LOG.trace("No strategy set for already processed docs,
beware of duplicates!");
+ Exchange exchange = createExchange(true);
+ exchange.getIn().setBody(doc);
+ exchange.getIn().setHeader(HEADER_ID, id);
+
+ if ("delete".equalsIgnoreCase(consumerProcessedStrategy)) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Deleting doc with ID {}", id);
+ }
+ CouchbaseCollectionOperation.removeDocument(collection, id,
endpoint.getWriteQueryTimeout(),
+ endpoint.getConsumerRetryPause());
+ } else if ("filter".equalsIgnoreCase(consumerProcessedStrategy)) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Filtering out ID {}", id);
}
+ } else {
+ LOG.trace("No strategy set for already processed docs, beware
of duplicates!");
+ }
- logDetails(id, doc, key, designDocumentName, viewName,
exchange);
- exchanges.add(exchange);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Created exchange = {}", exchange);
+ LOG.trace("Added Document in body = {}", doc);
+ LOG.trace("ID = {}", id);
}
- return processBatch(exchanges);
- } finally {
- lock.unlock();
+ exchanges.add(exchange);
+ }
+
+ return processBatch(exchanges);
+ }
+
+ @SuppressWarnings("deprecation")
+ private int pollWithView() throws Exception {
+ ViewResult result = bucket.viewQuery(endpoint.getDesignDocumentName(),
endpoint.getViewName(), this.viewOptions);
+
+ // okay we have some response from CouchBase so lets mark the consumer
as ready
+ forceConsumerAsReady();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("ViewResponse: {}", result);
+ }
+
+ String consumerProcessedStrategy =
endpoint.getConsumerProcessedStrategy();
+
+ Queue<Object> exchanges = new ArrayDeque<>();
+ for (ViewRow row : result.rows()) {
+ Object doc;
+ String id = row.id().get();
+ if (endpoint.isFullDocument()) {
+ doc = CouchbaseCollectionOperation.getDocument(collection, id,
endpoint.getQueryTimeout(),
+ endpoint.getConsumerRetryPause());
+ } else {
+ doc = row.valueAs(Object.class);
+ }
+
+ // Use String.class instead of the shaded JsonNode class to avoid
conflicts
+ // when Jackson is on the classpath (CAMEL-22090). The Couchbase
SDK's
+ // auto-detection of non-shaded Jackson would otherwise cause
deserialization
+ // failures when trying to deserialize into the shaded JsonNode
class.
+ String key = row.keyAs(String.class).orElse(null);
+ String designDocumentName = endpoint.getDesignDocumentName();
+ String viewName = endpoint.getViewName();
+
+ Exchange exchange = createExchange(true);
+ exchange.getIn().setBody(doc);
+ exchange.getIn().setHeader(HEADER_ID, id);
+ exchange.getIn().setHeader(HEADER_KEY, key);
+ exchange.getIn().setHeader(HEADER_DESIGN_DOCUMENT_NAME,
designDocumentName);
+ exchange.getIn().setHeader(HEADER_VIEWNAME, viewName);
+
+ if ("delete".equalsIgnoreCase(consumerProcessedStrategy)) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Deleting doc with ID {}", id);
+ }
+ CouchbaseCollectionOperation.removeDocument(collection, id,
endpoint.getWriteQueryTimeout(),
+ endpoint.getConsumerRetryPause());
+ } else if ("filter".equalsIgnoreCase(consumerProcessedStrategy)) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Filtering out ID {}", id);
+ }
+ // add filter for already processed docs
+ } else {
+ LOG.trace("No strategy set for already processed docs, beware
of duplicates!");
+ }
+
+ logDetails(id, doc, key, designDocumentName, viewName, exchange);
+ exchanges.add(exchange);
}
+
+ return processBatch(exchanges);
}
@Override
diff --git
a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
index 989a43da501d..93d7624efb64 100644
---
a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
+++
b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseEndpoint.java
@@ -56,7 +56,8 @@ import static
org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_QU
import static
org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_VIEWNAME;
/**
- * Query Couchbase Views with a poll strategy and/or perform various
operations against Couchbase databases.
+ * Query Couchbase databases using SQL++ (N1QL) queries or MapReduce Views
with a poll strategy and/or perform various
+ * operations against Couchbase databases.
*/
@UriEndpoint(firstVersion = "2.19.0", scheme = "couchbase", title =
"Couchbase", syntax = "couchbase:protocol://hostname:port",
category = { Category.DATABASE }, headersClass =
CouchbaseConstants.class)
@@ -114,10 +115,23 @@ public class CouchbaseEndpoint extends
ScheduledPollEndpoint implements Endpoint
@UriParam(label = "producer")
private long startingIdForInsertsFrom;
+
+ // SQL++ query
+ @UriParam(label = "consumer", defaultValue = "false",
+ description = "If true, use the deprecated MapReduce Views to
query documents via designDocumentName and viewName."
+ + " If false (default), use SQL++ queries
instead.")
+ private boolean useView;
+ @UriParam(label = "consumer")
+ private String statement;
+
// View control
- @UriParam(label = "consumer", defaultValue = DEFAULT_DESIGN_DOCUMENT_NAME)
+ @UriParam(label = "consumer", defaultValue = DEFAULT_DESIGN_DOCUMENT_NAME,
+ description = "The design document name to use. Deprecated: use
the statement option with SQL++ queries instead.")
+ @Deprecated
private String designDocumentName = DEFAULT_DESIGN_DOCUMENT_NAME;
- @UriParam(label = "consumer", defaultValue = DEFAULT_VIEWNAME)
+ @UriParam(label = "consumer", defaultValue = DEFAULT_VIEWNAME,
+ description = "The view name to use. Deprecated: use the
statement option with SQL++ queries instead.")
+ @Deprecated
private String viewName = DEFAULT_VIEWNAME;
@UriParam(label = "consumer", defaultValue = "-1")
private int limit = -1;
@@ -399,24 +413,109 @@ public class CouchbaseEndpoint extends
ScheduledPollEndpoint implements Endpoint
this.consumerRetryPause = consumerRetryPause;
}
+ public String getStatement() {
+ return statement;
+ }
+
+ /**
+ * A SQL++ (N1QL) query statement for consuming documents. When set, the
consumer uses SQL++ queries instead of
+ * MapReduce views. The query should select META().id AS __id to identify
documents. Example: SELECT META().id AS
+ * __id, * FROM `myCollection` WHERE type = 'order' LIMIT 100. If not set
and useView is false, a SQL++ query is
+ * auto-generated from the bucket, scope, collection, limit, skip,
descending, rangeStartKey, and rangeEndKey
+ * options.
+ */
+ public void setStatement(String statement) {
+ this.statement = statement;
+ }
+
+ public boolean isUseView() {
+ return useView;
+ }
+
+ /**
+ * If true, use the deprecated MapReduce Views to query documents via
designDocumentName and viewName. If false
+ * (default), use SQL++ queries instead. When both useView is false and
statement is not set, a SQL++ query is
+ * auto-generated from the endpoint options (limit, skip, descending,
etc.).
+ */
+ public void setUseView(boolean useView) {
+ this.useView = useView;
+ }
+
+ /**
+ * Builds a SQL++ query from the endpoint options.
+ */
+ String buildSqlQuery() {
+ StringBuilder sb = new StringBuilder("SELECT META().id AS __id, * FROM
`");
+ // Use the collection if set, otherwise use the bucket name (default
collection)
+ if (collection != null && !collection.isEmpty()) {
+ sb.append(collection);
+ } else {
+ sb.append(bucket);
+ }
+ sb.append('`');
+
+ // WHERE clause from range keys
+ String startKey = rangeStartKey;
+ String endKey = rangeEndKey;
+ boolean hasStart = startKey != null && !startKey.isEmpty();
+ boolean hasEnd = endKey != null && !endKey.isEmpty();
+ if (hasStart || hasEnd) {
+ sb.append(" WHERE ");
+ if (hasStart && hasEnd) {
+ sb.append("META().id >= '").append(startKey).append("' AND
META().id <= '").append(endKey).append('\'');
+ } else if (hasStart) {
+ sb.append("META().id >= '").append(startKey).append('\'');
+ } else {
+ sb.append("META().id <= '").append(endKey).append('\'');
+ }
+ }
+
+ // ORDER BY
+ if (descending) {
+ sb.append(" ORDER BY META().id DESC");
+ }
+
+ // LIMIT
+ if (limit > 0) {
+ sb.append(" LIMIT ").append(limit);
+ }
+
+ // OFFSET
+ if (skip > 0) {
+ sb.append(" OFFSET ").append(skip);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * @deprecated Use {@link #setStatement(String)} with SQL++ queries
instead.
+ */
+ @Deprecated
public String getDesignDocumentName() {
return designDocumentName;
}
/**
- * The design document name to use
+ * @deprecated Use {@link #setStatement(String)} with SQL++ queries
instead.
*/
+ @Deprecated
public void setDesignDocumentName(String designDocumentName) {
this.designDocumentName = designDocumentName;
}
+ /**
+ * @deprecated Use {@link #setStatement(String)} with SQL++ queries
instead.
+ */
+ @Deprecated
public String getViewName() {
return viewName;
}
/**
- * The view name to use
+ * @deprecated Use {@link #setStatement(String)} with SQL++ queries
instead.
*/
+ @Deprecated
public void setViewName(String viewName) {
this.viewName = viewName;
}
diff --git
a/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java
b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java
index c614e6c3726d..6d6f6ee8fd62 100644
---
a/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java
+++
b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/CouchbaseEndpointTest.java
@@ -173,6 +173,82 @@ public class CouchbaseEndpointTest {
endpoint.setDescending(false);
}
+ @Test
+ public void testBuildSqlQuerySimple() {
+ CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+ endpoint.setBucket("myBucket");
+ String query = endpoint.buildSqlQuery();
+ assertEquals("SELECT META().id AS __id, * FROM `myBucket`", query);
+ }
+
+ @Test
+ public void testBuildSqlQueryWithCollection() {
+ CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+ endpoint.setBucket("myBucket");
+ endpoint.setCollection("myCollection");
+ String query = endpoint.buildSqlQuery();
+ assertEquals("SELECT META().id AS __id, * FROM `myCollection`", query);
+ }
+
+ @Test
+ public void testBuildSqlQueryWithLimitAndSkip() {
+ CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+ endpoint.setBucket("myBucket");
+ endpoint.setLimit(10);
+ endpoint.setSkip(5);
+ String query = endpoint.buildSqlQuery();
+ assertEquals("SELECT META().id AS __id, * FROM `myBucket` LIMIT 10
OFFSET 5", query);
+ }
+
+ @Test
+ public void testBuildSqlQueryWithDescending() {
+ CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+ endpoint.setBucket("myBucket");
+ endpoint.setDescending(true);
+ endpoint.setLimit(10);
+ String query = endpoint.buildSqlQuery();
+ assertEquals("SELECT META().id AS __id, * FROM `myBucket` ORDER BY
META().id DESC LIMIT 10", query);
+ }
+
+ @Test
+ public void testBuildSqlQueryWithRangeKeys() {
+ CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+ endpoint.setBucket("myBucket");
+ endpoint.setRangeStartKey("docA");
+ endpoint.setRangeEndKey("docZ");
+ String query = endpoint.buildSqlQuery();
+ assertEquals(
+ "SELECT META().id AS __id, * FROM `myBucket` WHERE META().id
>= 'docA' AND META().id <= 'docZ'",
+ query);
+ }
+
+ @Test
+ public void testBuildSqlQueryWithStartKeyOnly() {
+ CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+ endpoint.setBucket("myBucket");
+ endpoint.setRangeStartKey("docA");
+ String query = endpoint.buildSqlQuery();
+ assertEquals("SELECT META().id AS __id, * FROM `myBucket` WHERE
META().id >= 'docA'", query);
+ }
+
+ @Test
+ public void testBuildSqlQueryFullOptions() {
+ CouchbaseEndpoint endpoint = new CouchbaseEndpoint();
+ endpoint.setBucket("myBucket");
+ endpoint.setCollection("orders");
+ endpoint.setRangeStartKey("order_001");
+ endpoint.setRangeEndKey("order_999");
+ endpoint.setDescending(true);
+ endpoint.setLimit(50);
+ endpoint.setSkip(10);
+ String query = endpoint.buildSqlQuery();
+ assertEquals(
+ "SELECT META().id AS __id, * FROM `orders`"
+ + " WHERE META().id >= 'order_001' AND META().id <=
'order_999'"
+ + " ORDER BY META().id DESC LIMIT 50 OFFSET 10",
+ query);
+ }
+
/**
* Verifies that the ClusterEnvironment is configured with
DefaultJsonSerializer to prevent the Couchbase SDK from
* auto-detecting non-shaded Jackson on the classpath (CAMEL-22090). When
non-shaded Jackson is present (e.g., via
diff --git
a/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/integration/ConsumeSqlQueryIT.java
b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/integration/ConsumeSqlQueryIT.java
new file mode 100644
index 000000000000..8da0ae899300
--- /dev/null
+++
b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/integration/ConsumeSqlQueryIT.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.couchbase.integration;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.manager.bucket.BucketSettings;
+import com.couchbase.client.java.manager.bucket.BucketType;
+import com.couchbase.client.java.manager.query.CreatePrimaryQueryIndexOptions;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.couchbase.CouchbaseConstants;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.infra.common.TestUtils;
+import org.apache.camel.test.infra.couchbase.services.CouchbaseService;
+import org.apache.camel.test.infra.couchbase.services.CouchbaseServiceFactory;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Tags;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*",
+ disabledReason = "Too resource intensive for most
systems to run reliably")
+@Tags({ @Tag("couchbase-71") })
+public class ConsumeSqlQueryIT extends CamelTestSupport {
+
+ @RegisterExtension
+ public static CouchbaseService service =
CouchbaseServiceFactory.createSingletonService();
+
+ protected static String bucketName;
+ protected static Cluster cluster;
+
+ @BeforeAll
+ static void setUpCouchbase() {
+ bucketName = "sqlBucket" + TestUtils.randomWithRange(0, 100);
+ cluster = Cluster.connect(service.getConnectionString(),
service.getUsername(), service.getPassword());
+
+ // Create bucket without specifying storage backend (uses server
default — Magma on 8.0+)
+ cluster.buckets().createBucket(
+
BucketSettings.create(bucketName).bucketType(BucketType.COUCHBASE).flushEnabled(true));
+
+ cluster.bucket(bucketName).waitUntilReady(Duration.ofSeconds(30));
+
+ // Create primary index for SQL++ queries
+ cluster.queryIndexes().createPrimaryIndex(bucketName,
+
CreatePrimaryQueryIndexOptions.createPrimaryQueryIndexOptions().ignoreIfExists(true));
+ }
+
+ @BeforeEach
+ public void waitForStarted() {
+ cluster.bucket(bucketName).waitUntilReady(Duration.ofSeconds(30));
+ }
+
+ @BeforeEach
+ public void addToBucket() {
+ for (int i = 0; i < 15; i++) {
+
cluster.bucket(bucketName).defaultCollection().upsert("DocumentID_" + i,
"message" + i);
+ }
+ }
+
+ @Test
+ public void testConsumeWithExplicitSqlQuery() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:explicit");
+ mock.expectedMinimumMessageCount(10);
+
+ MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
+
+ // Verify headers are set correctly
+ for (Exchange exchange : mock.getReceivedExchanges()) {
+ String id =
exchange.getIn().getHeader(CouchbaseConstants.HEADER_ID, String.class);
+ assertNotNull(id, "Document ID header should be set");
+ assertTrue(id.startsWith("DocumentID_"), "Document ID should match
inserted documents");
+ }
+ }
+
+ @Test
+ public void testConsumeWithAutoGeneratedSqlQuery() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:auto");
+ mock.expectedMinimumMessageCount(10);
+
+ MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
+
+ // Verify headers are set correctly with auto-generated SQL++
+ for (Exchange exchange : mock.getReceivedExchanges()) {
+ String id =
exchange.getIn().getHeader(CouchbaseConstants.HEADER_ID, String.class);
+ assertNotNull(id, "Document ID header should be set");
+ assertTrue(id.startsWith("DocumentID_"), "Document ID should match
inserted documents");
+ }
+ }
+
+ @Test
+ public void testConsumeWithSqlQueryRawResult() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:raw");
+ mock.expectedMinimumMessageCount(5);
+
+ MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS);
+
+ // With fullDocument=false, body should be the SQL++ query result row
(a JSON string)
+ for (Exchange exchange : mock.getReceivedExchanges()) {
+ Object body = exchange.getIn().getBody();
+ assertNotNull(body, "Body should not be null");
+ assertTrue(body instanceof String, "Body should be a String (JSON
row)");
+ }
+ }
+
+ @AfterEach
+ public void cleanBucket() {
+ cluster.buckets().flushBucket(bucketName);
+ }
+
+ @AfterAll
+ public static void tearDownCouchbase() {
+ cluster.buckets().dropBucket(bucketName);
+ cluster.disconnect();
+ }
+
+ public String getConnectionUri() {
+ return
String.format("couchbase:http://%s:%d?bucket=%s&username=%s&password=%s",
service.getHostname(),
+ service.getPort(), bucketName, service.getUsername(),
service.getPassword());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ // Explicit SQL++ statement
+ String explicitQuery = "SELECT META().id AS __id, * FROM `" +
bucketName + "` LIMIT 10";
+ from(getConnectionUri() + "&statement=" + explicitQuery)
+ .to("mock:explicit");
+
+ // Auto-generated SQL++ from endpoint options (no statement,
useView=false is the default)
+ from(getConnectionUri() + "&limit=10")
+ .to("mock:auto");
+
+ // SQL++ with fullDocument=false — uses raw query result row
as body
+ String rawQuery = "SELECT META().id AS __id, * FROM `" +
bucketName + "` LIMIT 5";
+ from(getConnectionUri() + "&statement=" + rawQuery +
"&fullDocument=false")
+ .to("mock:raw");
+ }
+ };
+ }
+}
diff --git
a/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/policy/HazelcastRoutePolicyIT.java
b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/policy/HazelcastRoutePolicyIT.java
new file mode 100644
index 000000000000..05ae33a243ba
--- /dev/null
+++
b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/policy/HazelcastRoutePolicyIT.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hazelcast.policy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+import com.hazelcast.config.Config;
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.test.infra.hazelcast.services.HazelcastService;
+import org.apache.camel.test.infra.hazelcast.services.HazelcastServiceFactory;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Integration test for {@link HazelcastRoutePolicy} that verifies leader
election and route management using Hazelcast
+ * distributed locks.
+ */
+public class HazelcastRoutePolicyIT {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(HazelcastRoutePolicyIT.class);
+
+ @RegisterExtension
+ public static HazelcastService hazelcastService =
HazelcastServiceFactory.createService();
+
+ private static final List<String> CLIENTS = IntStream.range(0,
3).mapToObj(Integer::toString).toList();
+ private static final List<String> RESULTS = new ArrayList<>();
+ private static final ScheduledExecutorService SCHEDULER =
Executors.newScheduledThreadPool(CLIENTS.size() * 2);
+ private static final CountDownLatch LATCH = new
CountDownLatch(CLIENTS.size());
+
+ @Test
+ public void test() throws Exception {
+ for (String id : CLIENTS) {
+ SCHEDULER.submit(() -> run(id));
+ }
+
+ LATCH.await(1, TimeUnit.MINUTES);
+ SCHEDULER.shutdownNow();
+
+ Assertions.assertEquals(CLIENTS.size(), RESULTS.size());
+ Assertions.assertTrue(RESULTS.containsAll(CLIENTS));
+ }
+
+ private static void run(String id) {
+ try {
+ int events = ThreadLocalRandom.current().nextInt(2, 6);
+ CountDownLatch contextLatch = new CountDownLatch(events);
+
+ Config config = hazelcastService.createConfiguration(null, 0,
"node-" + id, "set");
+ HazelcastInstance instance =
Hazelcast.newHazelcastInstance(config);
+
+ HazelcastRoutePolicy policy = new HazelcastRoutePolicy(instance);
+ policy.setLockMapName("camel-route-policy");
+ policy.setLockKey("my-lock");
+ policy.setLockValue("node-" + id);
+ policy.setTryLockTimeout(5, TimeUnit.SECONDS);
+
+ DefaultCamelContext context = new DefaultCamelContext();
+ context.disableJMX();
+ context.getCamelContextExtension().setName("context-" + id);
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("timer:hazelcast?delay=1000&period=1000")
+ .routeId("route-" + id)
+ .routePolicy(policy)
+ .log("From ${routeId}")
+ .process(e -> contextLatch.countDown());
+ }
+ });
+
+ // Staggered startup
+ Thread.sleep(ThreadLocalRandom.current().nextInt(500));
+
+ LOGGER.info("Starting CamelContext on node: {}", id);
+ context.start();
+ LOGGER.info("Started CamelContext on node: {}", id);
+
+ contextLatch.await(30, TimeUnit.SECONDS);
+
+ LOGGER.info("Shutting down node {}", id);
+ RESULTS.add(id);
+ context.stop();
+ instance.shutdown();
+ LATCH.countDown();
+ } catch (Exception e) {
+ LOGGER.warn("{}", e.getMessage(), e);
+ }
+ }
+}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_19.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_19.adoc
index ec451b9fbc2c..411bea6e0528 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_19.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_19.adoc
@@ -399,6 +399,20 @@ HttpRequest request =
context.getAttribute(AS2ClientManager.HTTP_REQUEST, HttpRe
HttpRequest request = context.getRequest();
----
+=== camel-couchbase
+
+The `designDocumentName` and `viewName` endpoint options are now deprecated.
MapReduce Views were
+deprecated in Couchbase Server 7.0 and do not work with the Magma storage
backend (default since
+Couchbase Server 8.0).
+
+The consumer now defaults to SQL++ (N1QL) queries instead of MapReduce Views.
A new `statement`
+endpoint option allows providing explicit SQL++ queries. When no `statement`
is set and `useView` is
+`false` (the default), the consumer auto-generates a SQL++ query from the
endpoint options
+(`bucket`, `collection`, `limit`, `skip`, `descending`, `rangeStartKey`,
`rangeEndKey`).
+
+To continue using the deprecated MapReduce Views, set `useView=true`
explicitly. See the component
+documentation for migration guidance.
+
=== camel-ftp
The `camel-ftp` component has been refactored to extract shared FTP/SFTP code
into a new `camel-ftp-common` module.
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
index f2d41840f684..92fe76e75500 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
@@ -1051,8 +1051,9 @@ public interface ComponentsBuilderFactory {
}
/**
* Couchbase (camel-couchbase)
- * Query Couchbase Views with a poll strategy and/or perform various
- * operations against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce Views
+ * with a poll strategy and/or perform various operations against Couchbase
+ * databases.
*
* Category: database
* Since: 2.19
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/CouchbaseComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/CouchbaseComponentBuilderFactory.java
index d6b456bac891..bcc6a32fb857 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/CouchbaseComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/CouchbaseComponentBuilderFactory.java
@@ -24,8 +24,8 @@ import org.apache.camel.builder.component.ComponentBuilder;
import org.apache.camel.component.couchbase.CouchbaseComponent;
/**
- * Query Couchbase Views with a poll strategy and/or perform various operations
- * against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce Views with a
+ * poll strategy and/or perform various operations against Couchbase databases.
*
* Generated by camel build tools - do NOT edit this file!
*/
@@ -34,8 +34,9 @@ public interface CouchbaseComponentBuilderFactory {
/**
* Couchbase (camel-couchbase)
- * Query Couchbase Views with a poll strategy and/or perform various
- * operations against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce Views
+ * with a poll strategy and/or perform various operations against Couchbase
+ * databases.
*
* Category: database
* Since: 2.19
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index d7e0a8d26b33..4a0f88874ac6 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -3263,8 +3263,9 @@ public class StaticEndpointBuilders {
}
/**
* Couchbase (camel-couchbase)
- * Query Couchbase Views with a poll strategy and/or perform various
- * operations against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce Views
+ * with a poll strategy and/or perform various operations against Couchbase
+ * databases.
*
* Category: database
* Since: 2.19
@@ -3290,8 +3291,9 @@ public class StaticEndpointBuilders {
}
/**
* Couchbase (camel-couchbase)
- * Query Couchbase Views with a poll strategy and/or perform various
- * operations against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce Views
+ * with a poll strategy and/or perform various operations against Couchbase
+ * databases.
*
* Category: database
* Since: 2.19
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CouchbaseEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CouchbaseEndpointBuilderFactory.java
index 33fb59d6ccb8..21e31040c8c4 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CouchbaseEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CouchbaseEndpointBuilderFactory.java
@@ -27,8 +27,8 @@ import org.apache.camel.builder.EndpointProducerBuilder;
import org.apache.camel.builder.endpoint.AbstractEndpointBuilder;
/**
- * Query Couchbase Views with a poll strategy and/or perform various operations
- * against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce Views with a
+ * poll strategy and/or perform various operations against Couchbase databases.
*
* Generated by camel build tools - do NOT edit this file!
*/
@@ -177,7 +177,8 @@ public interface CouchbaseEndpointBuilderFactory {
return this;
}
/**
- * The design document name to use.
+ * The design document name to use. Deprecated: use the statement
option
+ * with SQL queries instead.
*
* The option is a: <code>java.lang.String</code> type.
*
@@ -187,6 +188,7 @@ public interface CouchbaseEndpointBuilderFactory {
* @param designDocumentName the value to set
* @return the dsl builder
*/
+ @Deprecated
default CouchbaseEndpointConsumerBuilder designDocumentName(String
designDocumentName) {
doSetProperty("designDocumentName", designDocumentName);
return this;
@@ -344,7 +346,62 @@ public interface CouchbaseEndpointBuilderFactory {
return this;
}
/**
- * The view name to use.
+ * A SQL (N1QL) query statement for consuming documents. When set, the
+ * consumer uses SQL queries instead of MapReduce views. The query
+ * should select META().id AS __id to identify documents. Example:
+ * SELECT META().id AS __id, FROM myCollection WHERE type = 'order'
+ * LIMIT 100. If not set and useView is false, a SQL query is
+ * auto-generated from the bucket, scope, collection, limit, skip,
+ * descending, rangeStartKey, and rangeEndKey options.
+ *
+ * The option is a: <code>java.lang.String</code> type.
+ *
+ * Group: consumer
+ *
+ * @param statement the value to set
+ * @return the dsl builder
+ */
+ default CouchbaseEndpointConsumerBuilder statement(String statement) {
+ doSetProperty("statement", statement);
+ return this;
+ }
+ /**
+ * If true, use the deprecated MapReduce Views to query documents via
+ * designDocumentName and viewName. If false (default), use SQL queries
+ * instead.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: consumer
+ *
+ * @param useView the value to set
+ * @return the dsl builder
+ */
+ default CouchbaseEndpointConsumerBuilder useView(boolean useView) {
+ doSetProperty("useView", useView);
+ return this;
+ }
+ /**
+ * If true, use the deprecated MapReduce Views to query documents via
+ * designDocumentName and viewName. If false (default), use SQL queries
+ * instead.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: consumer
+ *
+ * @param useView the value to set
+ * @return the dsl builder
+ */
+ default CouchbaseEndpointConsumerBuilder useView(String useView) {
+ doSetProperty("useView", useView);
+ return this;
+ }
+ /**
+ * The view name to use. Deprecated: use the statement option with SQL
+ * queries instead.
*
* The option is a: <code>java.lang.String</code> type.
*
@@ -354,6 +411,7 @@ public interface CouchbaseEndpointBuilderFactory {
* @param viewName the value to set
* @return the dsl builder
*/
+ @Deprecated
default CouchbaseEndpointConsumerBuilder viewName(String viewName) {
doSetProperty("viewName", viewName);
return this;
@@ -1693,8 +1751,9 @@ public interface CouchbaseEndpointBuilderFactory {
public interface CouchbaseBuilders {
/**
* Couchbase (camel-couchbase)
- * Query Couchbase Views with a poll strategy and/or perform various
- * operations against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce
Views
+ * with a poll strategy and/or perform various operations against
+ * Couchbase databases.
*
* Category: database
* Since: 2.19
@@ -1707,8 +1766,9 @@ public interface CouchbaseEndpointBuilderFactory {
}
/**
* Couchbase (camel-couchbase)
- * Query Couchbase Views with a poll strategy and/or perform various
- * operations against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce
Views
+ * with a poll strategy and/or perform various operations against
+ * Couchbase databases.
*
* Category: database
* Since: 2.19
@@ -1734,8 +1794,9 @@ public interface CouchbaseEndpointBuilderFactory {
}
/**
* Couchbase (camel-couchbase)
- * Query Couchbase Views with a poll strategy and/or perform various
- * operations against Couchbase databases.
+ * Query Couchbase databases using SQL (N1QL) queries or MapReduce
Views
+ * with a poll strategy and/or perform various operations against
+ * Couchbase databases.
*
* Category: database
* Since: 2.19