This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch CAMEL-23218 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 19acad7211c50299a5783327009b1ddd8291b2fa Author: Guillaume Nodet <[email protected]> AuthorDate: Thu Mar 19 16:21:16 2026 +0100 CAMEL-23218: camel-couchbase - Add SQL++ (N1QL) query support for consumer The consumer now supports SQL++ queries as an alternative to the deprecated MapReduce Views. The new 'statement' endpoint option allows specifying a SQL++ query. When set, the consumer uses scope.query() instead of bucket.viewQuery(). The designDocumentName and viewName options are deprecated since MapReduce Views were deprecated in Couchbase Server 7.0 and don't work with Magma (default since Couchbase 8.0). Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../apache/camel/catalog/components/couchbase.json | 69 ++++---- .../couchbase/CouchbaseEndpointConfigurer.java | 3 + .../couchbase/CouchbaseEndpointUriFactory.java | 3 +- .../camel/component/couchbase/couchbase.json | 69 ++++---- .../src/main/docs/couchbase-component.adoc | 24 ++- .../component/couchbase/CouchbaseConsumer.java | 190 +++++++++++++++------ .../component/couchbase/CouchbaseEndpoint.java | 47 ++++- .../couchbase/integration/ConsumeSqlQueryIT.java | 117 +++++++++++++ .../ROOT/pages/camel-4x-upgrade-guide-4_19.adoc | 10 ++ .../dsl/CouchbaseEndpointBuilderFactory.java | 45 +++-- 10 files changed, 439 insertions(+), 138 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..af5a9324d4a2 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,45 @@ "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 [...] + "viewName": { "index": 18, "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": 19, "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": 20, "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": 21, "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": 22, "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": 23, "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": 24, "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": 25, "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": 26, "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": 27, "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": 28, "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": 29, "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": 30, "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": 31, "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": 32, "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": 33, "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": 34, "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": 35, "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": 36, "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": 37, "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": 38, "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": 39, "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": 40, "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": 41, "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": 42, "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": 43, "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": 44, "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": 45, "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": 46, "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": 47, "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": 48, "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": 49, "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..a42ba78da7fd 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,6 +95,7 @@ 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": @@ -181,6 +182,7 @@ 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": @@ -268,6 +270,7 @@ 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": 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..4a62315f7a35 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<>(50); props.add("additionalHosts"); props.add("autoStartIdForInserts"); props.add("backoffErrorThreshold"); @@ -69,6 +69,7 @@ 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("username"); 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..af5a9324d4a2 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,45 @@ "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 [...] + "viewName": { "index": 18, "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": 19, "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": 20, "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": 21, "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": 22, "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": 23, "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": 24, "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": 25, "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": 26, "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": 27, "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": 28, "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": 29, "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": 30, "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": 31, "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": 32, "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": 33, "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": 34, "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": 35, "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": 36, "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": 37, "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": 38, "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": 39, "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": 40, "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": 41, "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": 42, "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": 43, "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": 44, "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": 45, "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": 46, "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": 47, "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": 48, "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": 49, "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..6032f18f8bf3 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,28 @@ include::partial$component-endpoint-options.adoc[] include::partial$component-endpoint-headers.adoc[] // component options: END +== Consuming with SQL++ (N1QL) queries + +Since Couchbase Server 7.0, the recommended way to query documents is using SQL++ (formerly N1QL) instead of +MapReduce Views, which are deprecated since Couchbase 7.0 and do not work with the Magma storage backend +(default since Couchbase 8.0). + +To use SQL++ queries, set the `statement` endpoint option: + +[source,java] +---- +from("couchbase:http://localhost?bucket=myBucket&username=user&password=pass" + + "&statement=SELECT META().id AS __id, * FROM `myCollection` 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. + == 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..757c9c02e7f9 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,9 +52,12 @@ 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; @@ -66,11 +73,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 +85,13 @@ public class CouchbaseConsumer extends ScheduledBatchPollingConsumer implements this.collection = bucket.defaultCollection(); } + if (endpoint.getStatement() == null) { + initViewOptions(); + } + } + + @SuppressWarnings("deprecation") + private void initViewOptions() { this.viewOptions = ViewOptions.viewOptions(); int limit = endpoint.getLimit(); if (limit > 0) { @@ -120,66 +133,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 (endpoint.getStatement() != null) { + 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(endpoint.getStatement(), 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..056ab904f2e8 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", + 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 `myCollection` WHERE type = 'order' LIMIT 100") + 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,47 @@ 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 + */ + public void setStatement(String statement) { + this.statement = statement; + } + + /** + * @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/integration/ConsumeSqlQueryIT.java b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/integration/ConsumeSqlQueryIT.java new file mode 100644 index 000000000000..d97cd6f4e4ef --- /dev/null +++ b/components/camel-couchbase/src/test/java/org/apache/camel/component/couchbase/integration/ConsumeSqlQueryIT.java @@ -0,0 +1,117 @@ +/* + * 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.builder.RouteBuilder; +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; + +@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 testConsumeWithSqlQuery() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(10); + + MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS); + } + + @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() { + String query = "SELECT META().id AS __id, * FROM `" + bucketName + "` LIMIT 10"; + from(getConnectionUri() + "&statement=" + query) + .log("message received via SQL++") + .to("mock:result"); + } + }; + } +} 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..39fdb2a5cdd2 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,16 @@ HttpRequest request = context.getAttribute(AS2ClientManager.HTTP_REQUEST, HttpRe HttpRequest request = context.getRequest(); ---- +=== camel-couchbase + +The consumer now supports SQL++ (N1QL) queries as an alternative to the deprecated MapReduce Views. +Use the new `statement` endpoint option to specify a SQL++ query. When `statement` is set, the consumer +uses `scope.query()` instead of `bucket.viewQuery()`. + +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). Users should migrate to SQL++ queries using the `statement` option. + === 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-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..8f25d8dcbfc6 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,26 @@ 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. + * + * 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; + } + /** + * 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 +375,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 +1715,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 +1730,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 +1758,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
