From 40181cba51a0a332f1b1b007b8100d4412f6b276 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Mar 2026 21:52:50 +0100 Subject: [PATCH 01/20] CAMEL-21540: Add PGVector component for PostgreSQL vector database - New camel-pgvector component under components/camel-ai/ - Supports CREATE_TABLE, DROP_TABLE, UPSERT, DELETE, SIMILARITY_SEARCH actions - Uses PostgreSQL pgvector extension via JDBC with com.pgvector library - Supports cosine, euclidean, and inner product distance types - LangChain4j data type transformers: pgvector:embeddings and pgvector:rag - Integration tests with testcontainers pgvector image - LangChain4j embeddings integration test with AllMiniLmL6V2 model Co-Authored-By: Claude Opus 4.6 --- catalog/camel-allcomponents/pom.xml | 5 + .../camel-langchain4j-embeddings/pom.xml | 11 + ...4jEmbeddingsComponentPgVectorTargetIT.java | 141 +++++++++++ components/camel-ai/camel-pgvector/pom.xml | 90 +++++++ .../pgvector/PgVectorComponentConfigurer.java | 87 +++++++ .../PgVectorConfigurationConfigurer.java | 60 +++++ .../pgvector/PgVectorEndpointConfigurer.java | 71 ++++++ .../pgvector/PgVectorEndpointUriFactory.java | 74 ++++++ .../camel/component/pgvector/pgvector.json | 48 ++++ .../org/apache/camel/component.properties | 7 + .../org/apache/camel/component/pgvector | 2 + ...l.component.pgvector.PgVectorConfiguration | 2 + .../camel/configurer/pgvector-component | 2 + .../apache/camel/configurer/pgvector-endpoint | 2 + .../org/apache/camel/transformer.properties | 7 + .../camel/transformer/pgvector-embeddings | 2 + .../transformer/pgvector-embeddings.json | 14 ++ .../org/apache/camel/transformer/pgvector-rag | 2 + .../camel/transformer/pgvector-rag.json | 14 ++ .../apache/camel/urifactory/pgvector-endpoint | 2 + .../src/main/docs/pgvector-component.adoc | 60 +++++ .../camel/component/pgvector/PgVector.java | 24 ++ .../component/pgvector/PgVectorAction.java | 25 ++ .../component/pgvector/PgVectorComponent.java | 68 +++++ .../pgvector/PgVectorConfiguration.java | 100 ++++++++ .../component/pgvector/PgVectorEndpoint.java | 97 +++++++ .../component/pgvector/PgVectorHeaders.java | 44 ++++ .../component/pgvector/PgVectorProducer.java | 238 ++++++++++++++++++ ...PgVectorEmbeddingsDataTypeTransformer.java | 76 ++++++ ...rReverseEmbeddingsDataTypeTransformer.java | 46 ++++ .../pgvector/PgVectorComponentIT.java | 191 ++++++++++++++ components/camel-ai/pom.xml | 1 + parent/pom.xml | 6 + .../camel/maven/packaging/MojoHelper.java | 2 +- 34 files changed, 1620 insertions(+), 1 deletion(-) create mode 100644 components/camel-ai/camel-langchain4j-embeddings/src/test/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsComponentPgVectorTargetIT.java create mode 100644 components/camel-ai/camel-pgvector/pom.xml create mode 100644 components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java create mode 100644 components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java create mode 100644 components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java create mode 100644 components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointUriFactory.java create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component.properties create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component/pgvector create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.component.pgvector.PgVectorConfiguration create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-component create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-endpoint create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings.json create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag.json create mode 100644 components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/urifactory/pgvector-endpoint create mode 100644 components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVector.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorComponent.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorEndpoint.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java create mode 100644 components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml index 593117e20b1c2..ea92025722c8e 100644 --- a/catalog/camel-allcomponents/pom.xml +++ b/catalog/camel-allcomponents/pom.xml @@ -1692,6 +1692,11 @@ camel-pgevent ${project.version} + + org.apache.camel + camel-pgvector + ${project.version} + org.apache.camel camel-pinecone diff --git a/components/camel-ai/camel-langchain4j-embeddings/pom.xml b/components/camel-ai/camel-langchain4j-embeddings/pom.xml index 9ea004fe94ca0..9993ff4d88259 100644 --- a/components/camel-ai/camel-langchain4j-embeddings/pom.xml +++ b/components/camel-ai/camel-langchain4j-embeddings/pom.xml @@ -87,6 +87,11 @@ camel-milvus test + + org.apache.camel + camel-pgvector + test + org.apache.camel camel-pinecone @@ -156,6 +161,12 @@ ${project.version} test + + org.apache.camel + camel-test-infra-postgres + ${project.version} + test + org.apache.camel camel-test-infra-weaviate diff --git a/components/camel-ai/camel-langchain4j-embeddings/src/test/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsComponentPgVectorTargetIT.java b/components/camel-ai/camel-langchain4j-embeddings/src/test/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsComponentPgVectorTargetIT.java new file mode 100644 index 0000000000000..cb1f75b825ef8 --- /dev/null +++ b/components/camel-ai/camel-langchain4j-embeddings/src/test/java/org/apache/camel/component/langchain4j/embeddings/LangChain4jEmbeddingsComponentPgVectorTargetIT.java @@ -0,0 +1,141 @@ +/* + * 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.langchain4j.embeddings; + +import java.util.List; + +import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.pgvector.PgVector; +import org.apache.camel.component.pgvector.PgVectorAction; +import org.apache.camel.component.pgvector.PgVectorComponent; +import org.apache.camel.component.pgvector.PgVectorHeaders; +import org.apache.camel.spi.DataType; +import org.apache.camel.test.infra.postgres.services.PostgresService; +import org.apache.camel.test.infra.postgres.services.PostgresVectorServiceFactory; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.postgresql.ds.PGSimpleDataSource; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class LangChain4jEmbeddingsComponentPgVectorTargetIT extends CamelTestSupport { + + public static final String PGVECTOR_URI = "pgvector:embeddings"; + + @RegisterExtension + static PostgresService POSTGRES = PostgresVectorServiceFactory.createService(); + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + PGSimpleDataSource dataSource = new PGSimpleDataSource(); + dataSource.setUrl(POSTGRES.jdbcUrl()); + dataSource.setUser(POSTGRES.userName()); + dataSource.setPassword(POSTGRES.password()); + + PgVectorComponent component = context.getComponent(PgVector.SCHEME, PgVectorComponent.class); + component.getConfiguration().setDataSource(dataSource); + context.getRegistry().bind("embedding-model", new AllMiniLmL6V2EmbeddingModel()); + + return context; + } + + @Test + @Order(1) + public void createTable() { + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.CREATE_TABLE) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + } + + @Test + @Order(2) + public void upsertEmbedding() { + Exchange result = fluentTemplate.to("direct:in") + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) + .withHeader(PgVectorHeaders.RECORD_ID, "embed-1") + .withBody("The sky is blue") + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(String.class)).isEqualTo("embed-1"); + } + + @Test + @Order(3) + public void upsertSecondEmbedding() { + Exchange result = fluentTemplate.to("direct:in") + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) + .withHeader(PgVectorHeaders.RECORD_ID, "embed-2") + .withBody("The ocean is deep") + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + } + + @Test + @Order(4) + @SuppressWarnings("unchecked") + public void queryEmbeddings() { + Exchange result = fluentTemplate.to("direct:query") + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.SIMILARITY_SEARCH) + .withBody("blue sky") + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + + List results = result.getMessage().getBody(List.class); + assertThat(results).isNotEmpty(); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in") + .to("langchain4j-embeddings:test") + .transformDataType(new DataType("pgvector:embeddings")) + .to(PGVECTOR_URI); + + from("direct:query") + .to("langchain4j-embeddings:test") + .transformDataType(new DataType("pgvector:embeddings")) + .setHeader(PgVectorHeaders.ACTION, constant(PgVectorAction.SIMILARITY_SEARCH)) + .to(PGVECTOR_URI) + .transformDataType(new DataType("pgvector:rag")); + } + }; + } +} diff --git a/components/camel-ai/camel-pgvector/pom.xml b/components/camel-ai/camel-pgvector/pom.xml new file mode 100644 index 0000000000000..b02e9208d361a --- /dev/null +++ b/components/camel-ai/camel-pgvector/pom.xml @@ -0,0 +1,90 @@ + + + + 4.0.0 + + + camel-ai-parent + org.apache.camel + 4.19.0-SNAPSHOT + + + camel-pgvector + jar + Camel :: AI :: PGVector + Camel PGVector support + + + true + 4 + + + + + org.apache.camel + camel-support + + + + dev.langchain4j + langchain4j-core + ${langchain4j-version} + + + + org.postgresql + postgresql + ${pgjdbc-driver-version} + + + + com.pgvector + pgvector + ${pgvector-version} + + + + + org.apache.camel + camel-test-infra-postgres + ${project.version} + test + + + + + org.apache.camel + camel-test-junit6 + test + + + org.junit.jupiter + junit-jupiter + test + + + + org.assertj + assertj-core + test + + + + diff --git a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java new file mode 100644 index 0000000000000..c9b6b44f76369 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java @@ -0,0 +1,87 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.pgvector; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class PgVectorComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + private org.apache.camel.component.pgvector.PgVectorConfiguration getOrCreateConfiguration(PgVectorComponent target) { + if (target.getConfiguration() == null) { + target.setConfiguration(new org.apache.camel.component.pgvector.PgVectorConfiguration()); + } + return target.getConfiguration(); + } + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + PgVectorComponent target = (PgVectorComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; + case "configuration": target.setConfiguration(property(camelContext, org.apache.camel.component.pgvector.PgVectorConfiguration.class, value)); return true; + case "datasource": + case "dataSource": getOrCreateConfiguration(target).setDataSource(property(camelContext, javax.sql.DataSource.class, value)); return true; + case "dimension": getOrCreateConfiguration(target).setDimension(property(camelContext, int.class, value)); return true; + case "distancetype": + case "distanceType": getOrCreateConfiguration(target).setDistanceType(property(camelContext, java.lang.String.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + default: return false; + } + } + + @Override + public String[] getAutowiredNames() { + return new String[]{"dataSource"}; + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return boolean.class; + case "configuration": return org.apache.camel.component.pgvector.PgVectorConfiguration.class; + case "datasource": + case "dataSource": return javax.sql.DataSource.class; + case "dimension": return int.class; + case "distancetype": + case "distanceType": return java.lang.String.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + PgVectorComponent target = (PgVectorComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return target.isAutowiredEnabled(); + case "configuration": return target.getConfiguration(); + case "datasource": + case "dataSource": return getOrCreateConfiguration(target).getDataSource(); + case "dimension": return getOrCreateConfiguration(target).getDimension(); + case "distancetype": + case "distanceType": return getOrCreateConfiguration(target).getDistanceType(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + default: return null; + } + } +} + diff --git a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java new file mode 100644 index 0000000000000..8bedda0cef915 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java @@ -0,0 +1,60 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.pgvector; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.component.pgvector.PgVectorConfiguration; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.GenerateConfigurerMojo") +@SuppressWarnings("unchecked") +public class PgVectorConfigurationConfigurer extends org.apache.camel.support.component.PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + org.apache.camel.component.pgvector.PgVectorConfiguration target = (org.apache.camel.component.pgvector.PgVectorConfiguration) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "datasource": + case "dataSource": target.setDataSource(property(camelContext, javax.sql.DataSource.class, value)); return true; + case "dimension": target.setDimension(property(camelContext, int.class, value)); return true; + case "distancetype": + case "distanceType": target.setDistanceType(property(camelContext, java.lang.String.class, value)); return true; + default: return false; + } + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "datasource": + case "dataSource": return javax.sql.DataSource.class; + case "dimension": return int.class; + case "distancetype": + case "distanceType": return java.lang.String.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + org.apache.camel.component.pgvector.PgVectorConfiguration target = (org.apache.camel.component.pgvector.PgVectorConfiguration) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "datasource": + case "dataSource": return target.getDataSource(); + case "dimension": return target.getDimension(); + case "distancetype": + case "distanceType": return target.getDistanceType(); + default: return null; + } + } +} + diff --git a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java new file mode 100644 index 0000000000000..faa4cd7924937 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java @@ -0,0 +1,71 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.pgvector; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class PgVectorEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + PgVectorEndpoint target = (PgVectorEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "datasource": + case "dataSource": target.getConfiguration().setDataSource(property(camelContext, javax.sql.DataSource.class, value)); return true; + case "dimension": target.getConfiguration().setDimension(property(camelContext, int.class, value)); return true; + case "distancetype": + case "distanceType": target.getConfiguration().setDistanceType(property(camelContext, java.lang.String.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + default: return false; + } + } + + @Override + public String[] getAutowiredNames() { + return new String[]{"dataSource"}; + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "datasource": + case "dataSource": return javax.sql.DataSource.class; + case "dimension": return int.class; + case "distancetype": + case "distanceType": return java.lang.String.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + PgVectorEndpoint target = (PgVectorEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "datasource": + case "dataSource": return target.getConfiguration().getDataSource(); + case "dimension": return target.getConfiguration().getDimension(); + case "distancetype": + case "distanceType": return target.getConfiguration().getDistanceType(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + default: return null; + } + } +} + diff --git a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointUriFactory.java b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointUriFactory.java new file mode 100644 index 0000000000000..c41db64d0fcbe --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointUriFactory.java @@ -0,0 +1,74 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.pgvector; + +import javax.annotation.processing.Generated; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.camel.spi.EndpointUriFactory; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.GenerateEndpointUriFactoryMojo") +public class PgVectorEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory { + + private static final String BASE = ":collection"; + + private static final Set PROPERTY_NAMES; + private static final Set SECRET_PROPERTY_NAMES; + private static final Map MULTI_VALUE_PREFIXES; + static { + Set props = new HashSet<>(5); + props.add("collection"); + props.add("dataSource"); + props.add("dimension"); + props.add("distanceType"); + props.add("lazyStartProducer"); + PROPERTY_NAMES = Collections.unmodifiableSet(props); + SECRET_PROPERTY_NAMES = Collections.emptySet(); + MULTI_VALUE_PREFIXES = Collections.emptyMap(); + } + + @Override + public boolean isEnabled(String scheme) { + return "pgvector".equals(scheme); + } + + @Override + public String buildUri(String scheme, Map properties, boolean encode) throws URISyntaxException { + String syntax = scheme + BASE; + String uri = syntax; + + Map copy = new HashMap<>(properties); + + uri = buildPathParameter(syntax, uri, "collection", null, true, copy); + uri = buildQueryParameters(uri, copy, encode); + return uri; + } + + @Override + public Set propertyNames() { + return PROPERTY_NAMES; + } + + @Override + public Set secretPropertyNames() { + return SECRET_PROPERTY_NAMES; + } + + @Override + public Map multiValuePrefixes() { + return MULTI_VALUE_PREFIXES; + } + + @Override + public boolean isLenientProperties() { + return false; + } +} + diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json new file mode 100644 index 0000000000000..69d46599f91e7 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json @@ -0,0 +1,48 @@ +{ + "component": { + "kind": "component", + "name": "pgvector", + "title": "PGVector", + "description": "Perform operations on the PostgreSQL pgvector Vector Database.", + "deprecated": false, + "firstVersion": "4.19.0", + "label": "database,ai", + "javaType": "org.apache.camel.component.pgvector.PgVectorComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-pgvector", + "version": "4.19.0-SNAPSHOT", + "scheme": "pgvector", + "extendsScheme": "", + "syntax": "pgvector:collection", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": true, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.pgvector.PgVectorConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The configuration;" }, + "dataSource": { "index": 1, "kind": "property", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, + "dimension": { "index": 2, "kind": "property", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, + "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "lazyStartProducer": { "index": 4, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } + }, + "headers": { + "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, + "CamelPgVectorRecordId": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id of the vector record.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#RECORD_ID" }, + "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, + "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, + "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" } + }, + "properties": { + "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, + "dataSource": { "index": 1, "kind": "parameter", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, + "dimension": { "index": 2, "kind": "parameter", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, + "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "lazyStartProducer": { "index": 4, "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." } + } +} diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component.properties new file mode 100644 index 0000000000000..cad7e0ed66910 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +components=pgvector +groupId=org.apache.camel +artifactId=camel-pgvector +version=4.19.0-SNAPSHOT +projectName=Camel :: AI :: PGVector +projectDescription=Camel PGVector support diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component/pgvector b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component/pgvector new file mode 100644 index 0000000000000..3945951638c5b --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/component/pgvector @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.pgvector.PgVectorComponent diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.component.pgvector.PgVectorConfiguration b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.component.pgvector.PgVectorConfiguration new file mode 100644 index 0000000000000..cf12de7c025d5 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.component.pgvector.PgVectorConfiguration @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.pgvector.PgVectorConfigurationConfigurer diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-component b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-component new file mode 100644 index 0000000000000..fd431f002970f --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-component @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.pgvector.PgVectorComponentConfigurer diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-endpoint b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-endpoint new file mode 100644 index 0000000000000..483f077e2040f --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/configurer/pgvector-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.pgvector.PgVectorEndpointConfigurer diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties new file mode 100644 index 0000000000000..27a4f45b1c785 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +transformers=pgvector:embeddings pgvector:rag +groupId=org.apache.camel +artifactId=camel-pgvector +version=4.19.0-SNAPSHOT +projectName=Camel :: AI :: PGVector +projectDescription=Camel PGVector support diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings new file mode 100644 index 0000000000000..4b6963457fb08 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.pgvector.transform.PgVectorEmbeddingsDataTypeTransformer diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings.json b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings.json new file mode 100644 index 0000000000000..2a5efd26fd33d --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-embeddings.json @@ -0,0 +1,14 @@ +{ + "transformer": { + "kind": "transformer", + "name": "pgvector:embeddings", + "title": "Pgvector (Embeddings)", + "description": "Prepares the message to become an object writable by PgVector component", + "deprecated": false, + "javaType": "org.apache.camel.component.pgvector.transform.PgVectorEmbeddingsDataTypeTransformer", + "groupId": "org.apache.camel", + "artifactId": "camel-pgvector", + "version": "4.19.0-SNAPSHOT" + } +} + diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag new file mode 100644 index 0000000000000..8ddcd235af2a5 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.pgvector.transform.PgVectorReverseEmbeddingsDataTypeTransformer diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag.json b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag.json new file mode 100644 index 0000000000000..bde0480f57203 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/transformer/pgvector-rag.json @@ -0,0 +1,14 @@ +{ + "transformer": { + "kind": "transformer", + "name": "pgvector:rag", + "title": "Pgvector (Rag)", + "description": "Prepares the PgVector similarity search results to become a List of String for LangChain4j RAG", + "deprecated": false, + "javaType": "org.apache.camel.component.pgvector.transform.PgVectorReverseEmbeddingsDataTypeTransformer", + "groupId": "org.apache.camel", + "artifactId": "camel-pgvector", + "version": "4.19.0-SNAPSHOT" + } +} + diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/urifactory/pgvector-endpoint b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/urifactory/pgvector-endpoint new file mode 100644 index 0000000000000..a9f8e7a6c555d --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/services/org/apache/camel/urifactory/pgvector-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.pgvector.PgVectorEndpointUriFactory diff --git a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc new file mode 100644 index 0000000000000..6d2dca26aa999 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc @@ -0,0 +1,60 @@ += PGVector Component +:doctitle: PGVector +:shortname: pgvector +:artifactid: camel-pgvector +:description: Perform operations on the PostgreSQL pgvector Vector Database. +:since: 4.19 +:supportlevel: Preview +:tabs-sync-option: +:component-header: Only producer is supported +//Manually maintained attributes +:group: AI +:camel-spring-boot-name: pgvector + +*Since Camel {since}* + +*{component-header}* + +The PGVector Component provides support for interacting with https://github.com/pgvector/pgvector[pgvector], +the open-source vector similarity search extension for PostgreSQL. + +== URI format + +---- +pgvector:collection[?options] +---- + +Where *collection* represents the table name used to store vectors in the PostgreSQL database. + +== Configuring the DataSource + +A `javax.sql.DataSource` must be provided. It is recommended to use a connection pooling DataSource +(such as HikariCP) for production deployments. The DataSource can be set on the component or endpoint +configuration, or autowired from the registry. + +== Actions + +The following actions are supported via the `CamelPgVectorAction` header: + +- `CREATE_TABLE` - Creates the pgvector extension and a table with columns: id, text_content, metadata, embedding +- `DROP_TABLE` - Drops the table +- `UPSERT` - Inserts or updates a vector record. The body must be a `List`. Set `CamelPgVectorRecordId` for the ID (auto-generated UUID if not set), `CamelPgVectorTextContent` for text, and `CamelPgVectorMetadata` for metadata +- `DELETE` - Deletes a record by `CamelPgVectorRecordId` +- `SIMILARITY_SEARCH` - Searches for similar vectors. The body must be a `List` query vector. Set `CamelPgVectorQueryTopK` for max results (default 3). Returns a `List>` with keys: id, text_content, metadata, distance + +== LangChain4j Integration + +This component provides data type transformers for LangChain4j integration: + +- `pgvector:embeddings` - Transforms LangChain4j embedding output into a format suitable for the PGVector UPSERT action +- `pgvector:rag` - Transforms similarity search results into a `List` for RAG pipelines + + +// component options: START +include::partial$component-configure-options.adoc[] +include::partial$component-endpoint-options.adoc[] +include::partial$component-endpoint-headers.adoc[] +// component options: END + + +include::spring-boot:partial$starter.adoc[] diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVector.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVector.java new file mode 100644 index 0000000000000..0024a9375b6af --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVector.java @@ -0,0 +1,24 @@ +/* + * 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.pgvector; + +public class PgVector { + public static final String SCHEME = "pgvector"; + + private PgVector() { + } +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java new file mode 100644 index 0000000000000..1a647a4bc7a10 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java @@ -0,0 +1,25 @@ +/* + * 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.pgvector; + +public enum PgVectorAction { + CREATE_TABLE, + DROP_TABLE, + UPSERT, + DELETE, + SIMILARITY_SEARCH +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorComponent.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorComponent.java new file mode 100644 index 0000000000000..363050f9d4ca1 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorComponent.java @@ -0,0 +1,68 @@ +/* + * 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.pgvector; + +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.annotations.Component; +import org.apache.camel.support.DefaultComponent; + +@Component(PgVector.SCHEME) +public class PgVectorComponent extends DefaultComponent { + + @Metadata + private PgVectorConfiguration configuration; + + public PgVectorComponent() { + this(null); + } + + public PgVectorComponent(CamelContext context) { + super(context); + + this.configuration = new PgVectorConfiguration(); + } + + public PgVectorConfiguration getConfiguration() { + return configuration; + } + + /** + * The configuration; + */ + public void setConfiguration(PgVectorConfiguration configuration) { + this.configuration = configuration; + } + + @Override + protected Endpoint createEndpoint( + String uri, + String remaining, + Map parameters) + throws Exception { + + PgVectorConfiguration configuration = this.configuration.copy(); + + PgVectorEndpoint endpoint = new PgVectorEndpoint(uri, this, remaining, configuration); + setProperties(endpoint, parameters); + + return endpoint; + } +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java new file mode 100644 index 0000000000000..e61e1849f0971 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java @@ -0,0 +1,100 @@ +/* + * 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.pgvector; + +import java.util.Set; + +import javax.sql.DataSource; + +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.spi.Configurer; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; + +@Configurer +@UriParams +public class PgVectorConfiguration implements Cloneable { + + private static final Set VALID_DISTANCE_TYPES = Set.of("cosine", "euclidean", "innerProduct"); + + @Metadata(autowired = true, + description = "The DataSource to use for connecting to the PostgreSQL database with pgvector extension.") + @UriParam + private DataSource dataSource; + + @Metadata(label = "producer", + description = "The dimension of the vectors to store.") + @UriParam(defaultValue = "384") + private int dimension = 384; + + @Metadata(label = "producer", + description = "The distance type to use for similarity search.", + enums = "cosine,euclidean,innerProduct") + @UriParam(defaultValue = "cosine") + private String distanceType = "cosine"; + + public DataSource getDataSource() { + return dataSource; + } + + /** + * The DataSource to use for connecting to the PostgreSQL database with pgvector extension. + */ + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + public int getDimension() { + return dimension; + } + + /** + * The dimension of the vectors to store. + */ + public void setDimension(int dimension) { + this.dimension = dimension; + } + + public String getDistanceType() { + return distanceType; + } + + /** + * The distance type to use for similarity search. Supported values: cosine, euclidean, innerProduct. + */ + public void setDistanceType(String distanceType) { + if (!VALID_DISTANCE_TYPES.contains(distanceType)) { + throw new IllegalArgumentException( + "Invalid distanceType: " + distanceType + ". Valid values are: " + VALID_DISTANCE_TYPES); + } + this.distanceType = distanceType; + } + + // ************************ + // + // Clone + // + // ************************ + public PgVectorConfiguration copy() { + try { + return (PgVectorConfiguration) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeCamelException(e); + } + } +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorEndpoint.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorEndpoint.java new file mode 100644 index 0000000000000..a22f811cd0cb2 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorEndpoint.java @@ -0,0 +1,97 @@ +/* + * 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.pgvector; + +import javax.sql.DataSource; + +import org.apache.camel.Category; +import org.apache.camel.Component; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriPath; +import org.apache.camel.support.DefaultEndpoint; + +/** + * Perform operations on the PostgreSQL pgvector Vector Database. + */ +@UriEndpoint( + firstVersion = "4.19.0", + scheme = PgVector.SCHEME, + title = "PGVector", + syntax = "pgvector:collection", + producerOnly = true, + category = { + Category.DATABASE, + Category.AI + }, + headersClass = PgVectorHeaders.class) +public class PgVectorEndpoint extends DefaultEndpoint { + + @Metadata(required = true) + @UriPath(description = "The collection (table) name") + private final String collection; + + @UriParam + private PgVectorConfiguration configuration; + + public PgVectorEndpoint( + String endpointUri, + Component component, + String collection, + PgVectorConfiguration configuration) { + + super(endpointUri, component); + + this.collection = collection; + this.configuration = configuration; + } + + public PgVectorConfiguration getConfiguration() { + return configuration; + } + + public String getCollection() { + return collection; + } + + public DataSource getDataSource() { + return this.configuration.getDataSource(); + } + + @Override + public Producer createProducer() throws Exception { + return new PgVectorProducer(this); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + throw new UnsupportedOperationException("Consumer is not implemented for this component"); + } + + @Override + public void doStart() throws Exception { + super.doStart(); + + if (configuration.getDataSource() == null) { + throw new IllegalArgumentException("DataSource must be configured on the pgvector component or endpoint"); + } + } +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java new file mode 100644 index 0000000000000..eb80eec3fc071 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java @@ -0,0 +1,44 @@ +/* + * 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.pgvector; + +import org.apache.camel.spi.Metadata; + +public class PgVectorHeaders { + + @Metadata(description = "The action to be performed.", + javaType = "String", + enums = "CREATE_TABLE,DROP_TABLE,UPSERT,DELETE,SIMILARITY_SEARCH") + public static final String ACTION = "CamelPgVectorAction"; + + @Metadata(description = "The id of the vector record.", + javaType = "String") + public static final String RECORD_ID = "CamelPgVectorRecordId"; + + @Metadata(description = "The maximum number of results to return for similarity search.", + javaType = "Integer", defaultValue = "3") + public static final String QUERY_TOP_K = "CamelPgVectorQueryTopK"; + + @Metadata(description = "The text content to store alongside the vector embedding.", + javaType = "String") + public static final String TEXT_CONTENT = "CamelPgVectorTextContent"; + + @Metadata(description = "The metadata associated with the vector record, stored as JSON.", + javaType = "String") + public static final String METADATA = "CamelPgVectorMetadata"; + +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java new file mode 100644 index 0000000000000..02447160f59c2 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java @@ -0,0 +1,238 @@ +/* + * 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.pgvector; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.pgvector.PGvector; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.NoSuchHeaderException; +import org.apache.camel.support.DefaultProducer; +import org.apache.camel.support.ExchangeHelper; + +public class PgVectorProducer extends DefaultProducer { + + public PgVectorProducer(PgVectorEndpoint endpoint) { + super(endpoint); + } + + @Override + public PgVectorEndpoint getEndpoint() { + return (PgVectorEndpoint) super.getEndpoint(); + } + + @Override + public void process(Exchange exchange) { + final Message in = exchange.getMessage(); + final PgVectorAction action = in.getHeader(PgVectorHeaders.ACTION, PgVectorAction.class); + + try { + if (action == null) { + throw new NoSuchHeaderException("The action is a required header", exchange, PgVectorHeaders.ACTION); + } + + switch (action) { + case CREATE_TABLE: + createTable(exchange); + break; + case DROP_TABLE: + dropTable(exchange); + break; + case UPSERT: + upsert(exchange); + break; + case DELETE: + delete(exchange); + break; + case SIMILARITY_SEARCH: + similaritySearch(exchange); + break; + default: + throw new UnsupportedOperationException("Unsupported action: " + action.name()); + } + } catch (Exception e) { + exchange.setException(e); + } + } + + // *************************************** + // + // Actions + // + // *************************************** + + private void createTable(Exchange exchange) throws SQLException { + String tableName = getEndpoint().getCollection(); + int dimension = getEndpoint().getConfiguration().getDimension(); + + try (Connection conn = getEndpoint().getDataSource().getConnection()) { + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate("CREATE EXTENSION IF NOT EXISTS vector"); + } + + String sql = String.format( + "CREATE TABLE IF NOT EXISTS %s (" + + "id VARCHAR(36) PRIMARY KEY, " + + "text_content TEXT, " + + "metadata TEXT, " + + "embedding vector(%d))", + sanitizeIdentifier(tableName), dimension); + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate(sql); + } + + exchange.getMessage().setBody(true); + } + } + + private void dropTable(Exchange exchange) throws SQLException { + String tableName = getEndpoint().getCollection(); + + try (Connection conn = getEndpoint().getDataSource().getConnection()) { + String sql = String.format("DROP TABLE IF EXISTS %s", sanitizeIdentifier(tableName)); + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate(sql); + } + + exchange.getMessage().setBody(true); + } + } + + private void upsert(Exchange exchange) throws Exception { + final Message in = exchange.getMessage(); + String tableName = getEndpoint().getCollection(); + String id = in.getHeader(PgVectorHeaders.RECORD_ID, () -> UUID.randomUUID().toString(), String.class); + + List vector = in.getMandatoryBody(List.class); + float[] vectorArray = toFloatArray(vector); + + String textContent = in.getHeader(PgVectorHeaders.TEXT_CONTENT, String.class); + String metadata = in.getHeader(PgVectorHeaders.METADATA, String.class); + + String sql = String.format( + "INSERT INTO %s (id, text_content, metadata, embedding) VALUES (?, ?, ?, ?) " + + "ON CONFLICT (id) DO UPDATE SET text_content = EXCLUDED.text_content, " + + "metadata = EXCLUDED.metadata, embedding = EXCLUDED.embedding", + sanitizeIdentifier(tableName)); + + try (Connection conn = getEndpoint().getDataSource().getConnection()) { + PGvector.addVectorType(conn); + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, id); + pstmt.setString(2, textContent); + pstmt.setString(3, metadata); + pstmt.setObject(4, new PGvector(vectorArray)); + pstmt.executeUpdate(); + } + } + + exchange.getMessage().setBody(id); + } + + private void delete(Exchange exchange) throws Exception { + String tableName = getEndpoint().getCollection(); + String id = ExchangeHelper.getMandatoryHeader(exchange, PgVectorHeaders.RECORD_ID, String.class); + + String sql = String.format("DELETE FROM %s WHERE id = ?", sanitizeIdentifier(tableName)); + + try (Connection conn = getEndpoint().getDataSource().getConnection()) { + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, id); + int deleted = pstmt.executeUpdate(); + exchange.getMessage().setBody(deleted > 0); + } + } + } + + private void similaritySearch(Exchange exchange) throws Exception { + final Message in = exchange.getMessage(); + String tableName = getEndpoint().getCollection(); + int topK = in.getHeader(PgVectorHeaders.QUERY_TOP_K, 3, Integer.class); + String distanceType = getEndpoint().getConfiguration().getDistanceType(); + + List queryVector = in.getMandatoryBody(List.class); + float[] vectorArray = toFloatArray(queryVector); + + String distanceOp = getDistanceOperator(distanceType); + String sql = String.format( + "SELECT id, text_content, metadata, embedding %s ? AS distance FROM %s ORDER BY embedding %s ? LIMIT ?", + distanceOp, sanitizeIdentifier(tableName), distanceOp); + + try (Connection conn = getEndpoint().getDataSource().getConnection()) { + PGvector.addVectorType(conn); + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + PGvector pgVector = new PGvector(vectorArray); + pstmt.setObject(1, pgVector); + pstmt.setObject(2, pgVector); + pstmt.setInt(3, topK); + + try (ResultSet rs = pstmt.executeQuery()) { + List> results = new ArrayList<>(); + while (rs.next()) { + Map row = new HashMap<>(); + row.put("id", rs.getString("id")); + row.put("text_content", rs.getString("text_content")); + row.put("metadata", rs.getString("metadata")); + row.put("distance", rs.getDouble("distance")); + results.add(row); + } + exchange.getMessage().setBody(results); + } + } + } + } + + // *************************************** + // + // Helpers + // + // *************************************** + + private static float[] toFloatArray(List vector) { + float[] result = new float[vector.size()]; + for (int i = 0; i < vector.size(); i++) { + result[i] = vector.get(i); + } + return result; + } + + private static String getDistanceOperator(String distanceType) { + return switch (distanceType) { + case "euclidean" -> "<->"; + case "innerProduct" -> "<#>"; + case "cosine" -> "<=>"; + default -> throw new IllegalArgumentException("Unknown distance type: " + distanceType); + }; + } + + private static String sanitizeIdentifier(String identifier) { + if (!identifier.matches("[a-zA-Z_][a-zA-Z0-9_]*")) { + throw new IllegalArgumentException("Invalid SQL identifier: " + identifier); + } + return identifier; + } +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java new file mode 100644 index 0000000000000..166d8c64f958d --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java @@ -0,0 +1,76 @@ +/* + * 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.pgvector.transform; + +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import dev.langchain4j.data.document.Metadata; +import dev.langchain4j.data.embedding.Embedding; +import dev.langchain4j.data.segment.TextSegment; +import org.apache.camel.Message; +import org.apache.camel.ai.CamelLangchain4jAttributes; +import org.apache.camel.component.pgvector.PgVectorHeaders; +import org.apache.camel.spi.DataType; +import org.apache.camel.spi.DataTypeTransformer; +import org.apache.camel.spi.Transformer; + +/** + * Maps a LangChain4j Embeddings to a PgVector upsert message to write an embeddings vector on a PostgreSQL pgvector + * database. + */ +@DataTypeTransformer(name = "pgvector:embeddings", + description = "Prepares the message to become an object writable by PgVector component") +public class PgVectorEmbeddingsDataTypeTransformer extends Transformer { + + @Override + public void transform(Message message, DataType fromType, DataType toType) { + Embedding embedding + = message.getHeader(CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_EMBEDDING_VECTOR, Embedding.class); + TextSegment text = message.getBody(TextSegment.class); + + String id = message.getHeader(PgVectorHeaders.RECORD_ID, () -> UUID.randomUUID().toString(), String.class); + message.setHeader(PgVectorHeaders.RECORD_ID, id); + + message.setBody(embedding.vectorAsList()); + + if (text != null) { + message.setHeader(PgVectorHeaders.TEXT_CONTENT, text.text()); + Metadata metadata = text.metadata(); + if (metadata != null && !metadata.toMap().isEmpty()) { + message.setHeader(PgVectorHeaders.METADATA, toJson(metadata.toMap())); + } + } + } + + private static String toJson(Map map) { + return "{" + map.entrySet().stream() + .map(e -> "\"" + escapeJson(String.valueOf(e.getKey())) + "\":\"" + + escapeJson(String.valueOf(e.getValue())) + "\"") + .collect(Collectors.joining(",")) + + "}"; + } + + private static String escapeJson(String value) { + return value.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); + } +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java new file mode 100644 index 0000000000000..593b8f0f0c8a0 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java @@ -0,0 +1,46 @@ +/* + * 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.pgvector.transform; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.camel.Message; +import org.apache.camel.spi.DataType; +import org.apache.camel.spi.DataTypeTransformer; +import org.apache.camel.spi.Transformer; + +/** + * Maps a List of PgVector similarity search results to a List of String for LangChain4j RAG. + */ +@DataTypeTransformer(name = "pgvector:rag", + description = "Prepares the PgVector similarity search results to become a List of String for LangChain4j RAG") +public class PgVectorReverseEmbeddingsDataTypeTransformer extends Transformer { + + @Override + @SuppressWarnings("unchecked") + public void transform(Message message, DataType from, DataType to) throws Exception { + List> results = message.getBody(List.class); + + List textContents = results.stream() + .map(row -> (String) row.getOrDefault("text_content", "")) + .collect(Collectors.toList()); + + message.setBody(textContents); + } +} diff --git a/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java new file mode 100644 index 0000000000000..a157875e5fe34 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java @@ -0,0 +1,191 @@ +/* + * 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.pgvector; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.infra.postgres.services.PostgresService; +import org.apache.camel.test.infra.postgres.services.PostgresVectorServiceFactory; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.postgresql.ds.PGSimpleDataSource; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class PgVectorComponentIT extends CamelTestSupport { + + public static final String PGVECTOR_URI = "pgvector:test_embeddings"; + private static final int DIMENSION = 3; + + @RegisterExtension + static PostgresService POSTGRES = PostgresVectorServiceFactory.createService(); + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + PGSimpleDataSource dataSource = new PGSimpleDataSource(); + dataSource.setUrl(POSTGRES.jdbcUrl()); + dataSource.setUser(POSTGRES.userName()); + dataSource.setPassword(POSTGRES.password()); + + PgVectorComponent component = context.getComponent(PgVector.SCHEME, PgVectorComponent.class); + component.getConfiguration().setDataSource(dataSource); + component.getConfiguration().setDimension(DIMENSION); + + return context; + } + + @Test + @Order(1) + public void createTable() { + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.CREATE_TABLE) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(Boolean.class)).isTrue(); + } + + @Test + @Order(2) + public void upsert() { + List vector = Arrays.asList(0.1f, 0.2f, 0.3f); + + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) + .withHeader(PgVectorHeaders.RECORD_ID, "test-1") + .withHeader(PgVectorHeaders.TEXT_CONTENT, "Hello World") + .withHeader(PgVectorHeaders.METADATA, "source=test") + .withBody(vector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(String.class)).isEqualTo("test-1"); + } + + @Test + @Order(3) + public void upsertSecond() { + List vector = Arrays.asList(0.4f, 0.5f, 0.6f); + + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) + .withHeader(PgVectorHeaders.RECORD_ID, "test-2") + .withHeader(PgVectorHeaders.TEXT_CONTENT, "Goodbye World") + .withBody(vector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(String.class)).isEqualTo("test-2"); + } + + @Test + @Order(4) + @SuppressWarnings("unchecked") + public void similaritySearch() { + List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); + + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.SIMILARITY_SEARCH) + .withHeader(PgVectorHeaders.QUERY_TOP_K, 2) + .withBody(queryVector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + + List> results = result.getMessage().getBody(List.class); + assertThat(results).isNotEmpty(); + assertThat(results).hasSizeLessThanOrEqualTo(2); + + // The closest vector should be test-1 (exact match) + assertThat(results.get(0).get("id")).isEqualTo("test-1"); + assertThat(results.get(0).get("text_content")).isEqualTo("Hello World"); + } + + @Test + @Order(5) + public void delete() { + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DELETE) + .withHeader(PgVectorHeaders.RECORD_ID, "test-1") + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(Boolean.class)).isTrue(); + } + + @Test + @Order(6) + @SuppressWarnings("unchecked") + public void searchAfterDelete() { + List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); + + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.SIMILARITY_SEARCH) + .withHeader(PgVectorHeaders.QUERY_TOP_K, 2) + .withBody(queryVector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + + List> results = result.getMessage().getBody(List.class); + assertThat(results).hasSize(1); + assertThat(results.get(0).get("id")).isEqualTo("test-2"); + } + + @Test + @Order(7) + public void dropTable() { + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DROP_TABLE) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(Boolean.class)).isTrue(); + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in") + .to(PGVECTOR_URI); + } + }; + } +} diff --git a/components/camel-ai/pom.xml b/components/camel-ai/pom.xml index b3cc35116113e..d0d2ed952d817 100644 --- a/components/camel-ai/pom.xml +++ b/components/camel-ai/pom.xml @@ -52,6 +52,7 @@ camel-milvus camel-neo4j camel-openai + camel-pgvector camel-pinecone camel-qdrant camel-tensorflow-serving diff --git a/parent/pom.xml b/parent/pom.xml index b13caf1205240..6cb752702b1ca 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -460,6 +460,7 @@ 3.0.7 42.7.10 0.8.9 + 0.1.6 4.7.7 3.1.0 0.13.1 @@ -2386,6 +2387,11 @@ camel-pgevent ${project.version} + + org.apache.camel + camel-pgvector + ${project.version} + org.apache.camel camel-pinecone diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java index 4b0a6d66e0d01..46f7670f3996f 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java @@ -46,7 +46,7 @@ public static List getComponentPath(Path dir) { dir.resolve("camel-langchain4j-web-search"), dir.resolve("camel-qdrant"), dir.resolve("camel-milvus"), dir.resolve("camel-neo4j"), dir.resolve("camel-openai"), - dir.resolve("camel-pinecone"), dir.resolve("camel-kserve"), + dir.resolve("camel-pgvector"), dir.resolve("camel-pinecone"), dir.resolve("camel-kserve"), dir.resolve("camel-tensorflow-serving"), dir.resolve("camel-weaviate"), dir.resolve("camel-docling")); case "camel-as2": From 2c810f2db57d355b1d4168ba4e63699ec22effbb Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Mar 2026 22:19:28 +0100 Subject: [PATCH 02/20] CAMEL-21540: Add generated files for PGVector component Co-Authored-By: Claude Opus 4.6 --- bom/camel-bom/pom.xml | 5 + .../camel/catalog/components.properties | 11 +- .../camel/catalog/components/pgvector.json | 48 ++ .../camel/catalog/transformers.properties | 2 + .../transformers/pgvector-embeddings.json | 14 + .../catalog/transformers/pgvector-rag.json | 14 + .../apache/camel/main/components.properties | 11 +- .../modules/ROOT/examples/json/pgvector.json | 48 ++ docs/components/modules/ROOT/nav.adoc | 2 + .../ROOT/pages/pgvector-component.adoc | 60 ++ .../component/ComponentsBuilderFactory.java | 148 +---- .../dsl/PgvectorComponentBuilderFactory.java | 196 ++++++ .../endpoint/EndpointBuilderFactory.java | 1 + .../builder/endpoint/EndpointBuilders.java | 1 + .../endpoint/StaticEndpointBuilders.java | 580 ++---------------- .../dsl/PgVectorEndpointBuilderFactory.java | 319 ++++++++++ ...el-component-known-dependencies.properties | 1 + 17 files changed, 769 insertions(+), 692 deletions(-) create mode 100644 catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json create mode 100644 catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-embeddings.json create mode 100644 catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-rag.json create mode 100644 docs/components/modules/ROOT/examples/json/pgvector.json create mode 100644 docs/components/modules/ROOT/pages/pgvector-component.adoc create mode 100644 dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java create mode 100644 dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml index 4b93de1f546a1..e8668d2059c56 100644 --- a/bom/camel-bom/pom.xml +++ b/bom/camel-bom/pom.xml @@ -1902,6 +1902,11 @@ camel-pgevent 4.19.0-SNAPSHOT + + org.apache.camel + camel-pgvector + 4.19.0-SNAPSHOT + org.apache.camel camel-pinecone diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties index e9742912148af..5d09357914ed4 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties @@ -2,11 +2,9 @@ activemq activemq6 amqp arangodb -as2 asterisk atmosphere-websocket atom -avro aws-bedrock aws-bedrock-agent aws-bedrock-agent-runtime @@ -56,7 +54,6 @@ azure-storage-queue bean bean-validator bonita -box braintree browse caffeine-cache @@ -93,7 +90,6 @@ debezium-oracle debezium-postgres debezium-sqlserver dfdl -dhis2 digitalocean direct disruptor @@ -111,7 +107,6 @@ elasticsearch elasticsearch-rest-client event exec -fhir file file-watch flatpack @@ -217,7 +212,6 @@ jte kafka kamelet keycloak -knative kserve kubernetes-config-maps kubernetes-cronjob @@ -274,8 +268,6 @@ neo4j netty netty-http oaipmh -olingo2 -olingo4 once openai opensearch @@ -295,6 +287,7 @@ paho-mqtt5 pdf pg-replication-slot pgevent +pgvector pinecone platform-http plc4x @@ -315,13 +308,11 @@ robotframework rocketmq rss saga -salesforce sap-netweaver scheduler schematron scp seda -servicenow servlet sftp sjms diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json new file mode 100644 index 0000000000000..69d46599f91e7 --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json @@ -0,0 +1,48 @@ +{ + "component": { + "kind": "component", + "name": "pgvector", + "title": "PGVector", + "description": "Perform operations on the PostgreSQL pgvector Vector Database.", + "deprecated": false, + "firstVersion": "4.19.0", + "label": "database,ai", + "javaType": "org.apache.camel.component.pgvector.PgVectorComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-pgvector", + "version": "4.19.0-SNAPSHOT", + "scheme": "pgvector", + "extendsScheme": "", + "syntax": "pgvector:collection", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": true, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.pgvector.PgVectorConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The configuration;" }, + "dataSource": { "index": 1, "kind": "property", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, + "dimension": { "index": 2, "kind": "property", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, + "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "lazyStartProducer": { "index": 4, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } + }, + "headers": { + "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, + "CamelPgVectorRecordId": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id of the vector record.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#RECORD_ID" }, + "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, + "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, + "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" } + }, + "properties": { + "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, + "dataSource": { "index": 1, "kind": "parameter", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, + "dimension": { "index": 2, "kind": "parameter", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, + "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "lazyStartProducer": { "index": 4, "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." } + } +} diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties index c261164480cc8..51e76f50317c1 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties @@ -32,6 +32,8 @@ infinispan-embeddings milvus-embeddings neo4j-embeddings neo4j-rag +pgvector-embeddings +pgvector-rag pinecone-embeddings pinecone-rag protobuf-binary diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-embeddings.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-embeddings.json new file mode 100644 index 0000000000000..2a5efd26fd33d --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-embeddings.json @@ -0,0 +1,14 @@ +{ + "transformer": { + "kind": "transformer", + "name": "pgvector:embeddings", + "title": "Pgvector (Embeddings)", + "description": "Prepares the message to become an object writable by PgVector component", + "deprecated": false, + "javaType": "org.apache.camel.component.pgvector.transform.PgVectorEmbeddingsDataTypeTransformer", + "groupId": "org.apache.camel", + "artifactId": "camel-pgvector", + "version": "4.19.0-SNAPSHOT" + } +} + diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-rag.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-rag.json new file mode 100644 index 0000000000000..bde0480f57203 --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pgvector-rag.json @@ -0,0 +1,14 @@ +{ + "transformer": { + "kind": "transformer", + "name": "pgvector:rag", + "title": "Pgvector (Rag)", + "description": "Prepares the PgVector similarity search results to become a List of String for LangChain4j RAG", + "deprecated": false, + "javaType": "org.apache.camel.component.pgvector.transform.PgVectorReverseEmbeddingsDataTypeTransformer", + "groupId": "org.apache.camel", + "artifactId": "camel-pgvector", + "version": "4.19.0-SNAPSHOT" + } +} + diff --git a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties index e9742912148af..5d09357914ed4 100644 --- a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties +++ b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties @@ -2,11 +2,9 @@ activemq activemq6 amqp arangodb -as2 asterisk atmosphere-websocket atom -avro aws-bedrock aws-bedrock-agent aws-bedrock-agent-runtime @@ -56,7 +54,6 @@ azure-storage-queue bean bean-validator bonita -box braintree browse caffeine-cache @@ -93,7 +90,6 @@ debezium-oracle debezium-postgres debezium-sqlserver dfdl -dhis2 digitalocean direct disruptor @@ -111,7 +107,6 @@ elasticsearch elasticsearch-rest-client event exec -fhir file file-watch flatpack @@ -217,7 +212,6 @@ jte kafka kamelet keycloak -knative kserve kubernetes-config-maps kubernetes-cronjob @@ -274,8 +268,6 @@ neo4j netty netty-http oaipmh -olingo2 -olingo4 once openai opensearch @@ -295,6 +287,7 @@ paho-mqtt5 pdf pg-replication-slot pgevent +pgvector pinecone platform-http plc4x @@ -315,13 +308,11 @@ robotframework rocketmq rss saga -salesforce sap-netweaver scheduler schematron scp seda -servicenow servlet sftp sjms diff --git a/docs/components/modules/ROOT/examples/json/pgvector.json b/docs/components/modules/ROOT/examples/json/pgvector.json new file mode 100644 index 0000000000000..69d46599f91e7 --- /dev/null +++ b/docs/components/modules/ROOT/examples/json/pgvector.json @@ -0,0 +1,48 @@ +{ + "component": { + "kind": "component", + "name": "pgvector", + "title": "PGVector", + "description": "Perform operations on the PostgreSQL pgvector Vector Database.", + "deprecated": false, + "firstVersion": "4.19.0", + "label": "database,ai", + "javaType": "org.apache.camel.component.pgvector.PgVectorComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-pgvector", + "version": "4.19.0-SNAPSHOT", + "scheme": "pgvector", + "extendsScheme": "", + "syntax": "pgvector:collection", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": true, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.pgvector.PgVectorConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The configuration;" }, + "dataSource": { "index": 1, "kind": "property", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, + "dimension": { "index": 2, "kind": "property", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, + "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "lazyStartProducer": { "index": 4, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } + }, + "headers": { + "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, + "CamelPgVectorRecordId": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id of the vector record.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#RECORD_ID" }, + "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, + "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, + "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" } + }, + "properties": { + "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, + "dataSource": { "index": 1, "kind": "parameter", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, + "dimension": { "index": 2, "kind": "parameter", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, + "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "lazyStartProducer": { "index": 4, "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." } + } +} diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc index cfc430edd163d..aa815ab07e081 100644 --- a/docs/components/modules/ROOT/nav.adoc +++ b/docs/components/modules/ROOT/nav.adoc @@ -19,6 +19,7 @@ *** xref:milvus-component.adoc[Milvus] *** xref:neo4j-component.adoc[Neo4j] *** xref:openai-component.adoc[OpenAI] +*** xref:pgvector-component.adoc[PGVector] *** xref:pinecone-component.adoc[Pinecone] *** xref:qdrant-component.adoc[Qdrant] *** xref:spring-ai-chat-component.adoc[Spring AI Chat] @@ -314,6 +315,7 @@ ** xref:pdf-component.adoc[PDF] ** xref:platform-http-component.adoc[Platform HTTP] ** xref:plc4x-component.adoc[PLC4X] +** xref:pgvector-component.adoc[PGVector] ** xref:pgevent-component.adoc[PostgresSQL Event] ** xref:pg-replication-slot-component.adoc[PostgresSQL Replication Slot] ** xref:pqc-component.adoc[PQC Algorithms] diff --git a/docs/components/modules/ROOT/pages/pgvector-component.adoc b/docs/components/modules/ROOT/pages/pgvector-component.adoc new file mode 100644 index 0000000000000..6d2dca26aa999 --- /dev/null +++ b/docs/components/modules/ROOT/pages/pgvector-component.adoc @@ -0,0 +1,60 @@ += PGVector Component +:doctitle: PGVector +:shortname: pgvector +:artifactid: camel-pgvector +:description: Perform operations on the PostgreSQL pgvector Vector Database. +:since: 4.19 +:supportlevel: Preview +:tabs-sync-option: +:component-header: Only producer is supported +//Manually maintained attributes +:group: AI +:camel-spring-boot-name: pgvector + +*Since Camel {since}* + +*{component-header}* + +The PGVector Component provides support for interacting with https://github.com/pgvector/pgvector[pgvector], +the open-source vector similarity search extension for PostgreSQL. + +== URI format + +---- +pgvector:collection[?options] +---- + +Where *collection* represents the table name used to store vectors in the PostgreSQL database. + +== Configuring the DataSource + +A `javax.sql.DataSource` must be provided. It is recommended to use a connection pooling DataSource +(such as HikariCP) for production deployments. The DataSource can be set on the component or endpoint +configuration, or autowired from the registry. + +== Actions + +The following actions are supported via the `CamelPgVectorAction` header: + +- `CREATE_TABLE` - Creates the pgvector extension and a table with columns: id, text_content, metadata, embedding +- `DROP_TABLE` - Drops the table +- `UPSERT` - Inserts or updates a vector record. The body must be a `List`. Set `CamelPgVectorRecordId` for the ID (auto-generated UUID if not set), `CamelPgVectorTextContent` for text, and `CamelPgVectorMetadata` for metadata +- `DELETE` - Deletes a record by `CamelPgVectorRecordId` +- `SIMILARITY_SEARCH` - Searches for similar vectors. The body must be a `List` query vector. Set `CamelPgVectorQueryTopK` for max results (default 3). Returns a `List>` with keys: id, text_content, metadata, distance + +== LangChain4j Integration + +This component provides data type transformers for LangChain4j integration: + +- `pgvector:embeddings` - Transforms LangChain4j embedding output into a format suitable for the PGVector UPSERT action +- `pgvector:rag` - Transforms similarity search results into a `List` for RAG pipelines + + +// component options: START +include::partial$component-configure-options.adoc[] +include::partial$component-endpoint-options.adoc[] +include::partial$component-endpoint-headers.adoc[] +// component options: END + + +include::spring-boot:partial$starter.adoc[] 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 e21c19160c095..3e5b62df1f47a 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 @@ -100,19 +100,6 @@ static AmqpComponentBuilderFactory.AmqpComponentBuilder amqp() { static ArangodbComponentBuilderFactory.ArangodbComponentBuilder arangodb() { return ArangodbComponentBuilderFactory.arangodb(); } - /** - * AS2 (camel-as2) - * Transfer data securely and reliably using the AS2 protocol (RFC4130). - * - * Category: file - * Since: 2.22 - * Maven coordinates: org.apache.camel:camel-as2 - * - * @return the dsl builder - */ - static As2ComponentBuilderFactory.As2ComponentBuilder as2() { - return As2ComponentBuilderFactory.as2(); - } /** * Asterisk (camel-asterisk) * Interact with Asterisk PBX Server (VoIP). @@ -152,19 +139,6 @@ static AtmosphereWebsocketComponentBuilderFactory.AtmosphereWebsocketComponentBu static AtomComponentBuilderFactory.AtomComponentBuilder atom() { return AtomComponentBuilderFactory.atom(); } - /** - * Avro RPC (camel-avro-rpc) - * Produce or consume Apache Avro RPC services. - * - * Category: rpc - * Since: 2.10 - * Maven coordinates: org.apache.camel:camel-avro-rpc - * - * @return the dsl builder - */ - static AvroComponentBuilderFactory.AvroComponentBuilder avro() { - return AvroComponentBuilderFactory.avro(); - } /** * AWS Bedrock (camel-aws-bedrock) * Invoke Model of AWS Bedrock service. @@ -807,20 +781,6 @@ static BeanValidatorComponentBuilderFactory.BeanValidatorComponentBuilder beanVa static BonitaComponentBuilderFactory.BonitaComponentBuilder bonita() { return BonitaComponentBuilderFactory.bonita(); } - /** - * Box (camel-box) - * Upload, download and manage files, folders, groups, collaborations, etc. - * on box.com. - * - * Category: cloud,file,api - * Since: 2.14 - * Maven coordinates: org.apache.camel:camel-box - * - * @return the dsl builder - */ - static BoxComponentBuilderFactory.BoxComponentBuilder box() { - return BoxComponentBuilderFactory.box(); - } /** * Braintree (camel-braintree) * Process payments using Braintree Payments. @@ -1307,20 +1267,6 @@ static DebeziumSqlserverComponentBuilderFactory.DebeziumSqlserverComponentBuilde static DfdlComponentBuilderFactory.DfdlComponentBuilder dfdl() { return DfdlComponentBuilderFactory.dfdl(); } - /** - * DHIS2 (camel-dhis2) - * Leverages the DHIS2 Java SDK to integrate Apache Camel with the DHIS2 Web - * API. - * - * Category: api - * Since: 4.0 - * Maven coordinates: org.apache.camel:camel-dhis2 - * - * @return the dsl builder - */ - static Dhis2ComponentBuilderFactory.Dhis2ComponentBuilder dhis2() { - return Dhis2ComponentBuilderFactory.dhis2(); - } /** * DigitalOcean (camel-digitalocean) * Manage Droplets and resources within the DigitalOcean cloud. @@ -1549,20 +1495,6 @@ static EventComponentBuilderFactory.EventComponentBuilder event() { static ExecComponentBuilderFactory.ExecComponentBuilder exec() { return ExecComponentBuilderFactory.exec(); } - /** - * FHIR (camel-fhir) - * Exchange information in the healthcare domain using the FHIR (Fast - * Healthcare Interoperability Resources) standard. - * - * Category: api - * Since: 2.23 - * Maven coordinates: org.apache.camel:camel-fhir - * - * @return the dsl builder - */ - static FhirComponentBuilderFactory.FhirComponentBuilder fhir() { - return FhirComponentBuilderFactory.fhir(); - } /** * File (camel-file) * Read and write files. @@ -2956,19 +2888,6 @@ static KameletComponentBuilderFactory.KameletComponentBuilder kamelet() { static KeycloakComponentBuilderFactory.KeycloakComponentBuilder keycloak() { return KeycloakComponentBuilderFactory.keycloak(); } - /** - * Knative (camel-knative) - * Send and receive events from Knative. - * - * Category: cloud - * Since: 3.15 - * Maven coordinates: org.apache.camel:camel-knative - * - * @return the dsl builder - */ - static KnativeComponentBuilderFactory.KnativeComponentBuilder knative() { - return KnativeComponentBuilderFactory.knative(); - } /** * KServe (camel-kserve) * Provide access to AI model servers with the KServe standard to run @@ -3717,32 +3636,6 @@ static NettyHttpComponentBuilderFactory.NettyHttpComponentBuilder nettyHttp() { static OaipmhComponentBuilderFactory.OaipmhComponentBuilder oaipmh() { return OaipmhComponentBuilderFactory.oaipmh(); } - /** - * Olingo2 (camel-olingo2) - * Communicate with OData 2.0 services using Apache Olingo. - * - * Category: cloud - * Since: 2.14 - * Maven coordinates: org.apache.camel:camel-olingo2 - * - * @return the dsl builder - */ - static Olingo2ComponentBuilderFactory.Olingo2ComponentBuilder olingo2() { - return Olingo2ComponentBuilderFactory.olingo2(); - } - /** - * Olingo4 (camel-olingo4) - * Communicate with OData 4.0 services using Apache Olingo OData API. - * - * Category: cloud - * Since: 2.19 - * Maven coordinates: org.apache.camel:camel-olingo4 - * - * @return the dsl builder - */ - static Olingo4ComponentBuilderFactory.Olingo4ComponentBuilder olingo4() { - return Olingo4ComponentBuilderFactory.olingo4(); - } /** * Once (camel-once) * Trigger a single message only once at startup (useful for development and @@ -3994,6 +3887,19 @@ static PgReplicationSlotComponentBuilderFactory.PgReplicationSlotComponentBuilde static PgeventComponentBuilderFactory.PgeventComponentBuilder pgevent() { return PgeventComponentBuilderFactory.pgevent(); } + /** + * PGVector (camel-pgvector) + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Category: database,ai + * Since: 4.19 + * Maven coordinates: org.apache.camel:camel-pgvector + * + * @return the dsl builder + */ + static PgvectorComponentBuilderFactory.PgvectorComponentBuilder pgvector() { + return PgvectorComponentBuilderFactory.pgvector(); + } /** * Pinecone (camel-pinecone) * Perform operations on the Pinecone Vector Database. @@ -4197,7 +4103,7 @@ static RestApiComponentBuilderFactory.RestApiComponentBuilder restApi() { } /** * REST OpenApi (camel-rest-openapi) - * To call and expose REST services using OpenAPI specification as contract. + * To call REST services using OpenAPI specification as contract. * * Category: rest,api * Since: 3.1 @@ -4260,19 +4166,6 @@ static RssComponentBuilderFactory.RssComponentBuilder rss() { static SagaComponentBuilderFactory.SagaComponentBuilder saga() { return SagaComponentBuilderFactory.saga(); } - /** - * Salesforce (camel-salesforce) - * Communicate with Salesforce using Java DTOs. - * - * Category: cloud,saas - * Since: 2.12 - * Maven coordinates: org.apache.camel:camel-salesforce - * - * @return the dsl builder - */ - static SalesforceComponentBuilderFactory.SalesforceComponentBuilder salesforce() { - return SalesforceComponentBuilderFactory.salesforce(); - } /** * SAP NetWeaver (camel-sap-netweaver) * Send requests to SAP NetWeaver Gateway using HTTP. @@ -4340,19 +4233,6 @@ static ScpComponentBuilderFactory.ScpComponentBuilder scp() { static SedaComponentBuilderFactory.SedaComponentBuilder seda() { return SedaComponentBuilderFactory.seda(); } - /** - * ServiceNow (camel-servicenow) - * Interact with ServiceNow via its REST API. - * - * Category: api,cloud,management - * Since: 2.18 - * Maven coordinates: org.apache.camel:camel-servicenow - * - * @return the dsl builder - */ - static ServicenowComponentBuilderFactory.ServicenowComponentBuilder servicenow() { - return ServicenowComponentBuilderFactory.servicenow(); - } /** * Servlet (camel-servlet) * Serve HTTP requests by a Servlet. diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java new file mode 100644 index 0000000000000..564df1a3f7492 --- /dev/null +++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java @@ -0,0 +1,196 @@ +/* Generated by camel build tools - do NOT edit this file! */ +/* + * 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.builder.component.dsl; + +import javax.annotation.processing.Generated; +import org.apache.camel.Component; +import org.apache.camel.builder.component.AbstractComponentBuilder; +import org.apache.camel.builder.component.ComponentBuilder; +import org.apache.camel.component.pgvector.PgVectorComponent; + +/** + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.ComponentDslMojo") +public interface PgvectorComponentBuilderFactory { + + /** + * PGVector (camel-pgvector) + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Category: database,ai + * Since: 4.19 + * Maven coordinates: org.apache.camel:camel-pgvector + * + * @return the dsl builder + */ + static PgvectorComponentBuilder pgvector() { + return new PgvectorComponentBuilderImpl(); + } + + /** + * Builder for the PGVector component. + */ + interface PgvectorComponentBuilder extends ComponentBuilder { + + /** + * The configuration;. + * + * The option is a: + * <code>org.apache.camel.component.pgvector.PgVectorConfiguration</code> type. + * + * Group: producer + * + * @param configuration the value to set + * @return the dsl builder + */ + default PgvectorComponentBuilder configuration(org.apache.camel.component.pgvector.PgVectorConfiguration configuration) { + doSetProperty("configuration", configuration); + return this; + } + + /** + * The DataSource to use for connecting to the PostgreSQL database with + * pgvector extension. + * + * The option is a: <code>javax.sql.DataSource</code> type. + * + * Group: producer + * + * @param dataSource the value to set + * @return the dsl builder + */ + default PgvectorComponentBuilder dataSource(javax.sql.DataSource dataSource) { + doSetProperty("dataSource", dataSource); + return this; + } + + + /** + * The dimension of the vectors to store. + * + * The option is a: <code>int</code> type. + * + * Default: 384 + * Group: producer + * + * @param dimension the value to set + * @return the dsl builder + */ + default PgvectorComponentBuilder dimension(int dimension) { + doSetProperty("dimension", dimension); + return this; + } + + + /** + * The distance type to use for similarity search. + * + * The option is a: <code>java.lang.String</code> type. + * + * Default: cosine + * Group: producer + * + * @param distanceType the value to set + * @return the dsl builder + */ + default PgvectorComponentBuilder distanceType(java.lang.String distanceType) { + doSetProperty("distanceType", distanceType); + return this; + } + + + /** + * 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 producer may otherwise fail during + * starting and cause the route to fail being started. By deferring this + * startup to be lazy then the startup failure can be handled during + * routing messages via Camel's routing error handlers. Beware that when + * the first message is processed then creating and starting the + * producer may take a little time and prolong the total processing time + * of the processing. + * + * The option is a: <code>boolean</code> type. + * + * Default: false + * Group: producer + * + * @param lazyStartProducer the value to set + * @return the dsl builder + */ + default PgvectorComponentBuilder lazyStartProducer(boolean lazyStartProducer) { + doSetProperty("lazyStartProducer", lazyStartProducer); + return this; + } + + + /** + * Whether autowiring is enabled. This is used for automatic autowiring + * options (the option must be marked as autowired) by looking up in the + * registry to find if there is a single instance of matching type, + * which then gets configured on the component. This can be used for + * automatic configuring JDBC data sources, JMS connection factories, + * AWS Clients, etc. + * + * The option is a: <code>boolean</code> type. + * + * Default: true + * Group: advanced + * + * @param autowiredEnabled the value to set + * @return the dsl builder + */ + default PgvectorComponentBuilder autowiredEnabled(boolean autowiredEnabled) { + doSetProperty("autowiredEnabled", autowiredEnabled); + return this; + } + } + + class PgvectorComponentBuilderImpl + extends AbstractComponentBuilder + implements PgvectorComponentBuilder { + @Override + protected PgVectorComponent buildConcreteComponent() { + return new PgVectorComponent(); + } + private org.apache.camel.component.pgvector.PgVectorConfiguration getOrCreateConfiguration(PgVectorComponent component) { + if (component.getConfiguration() == null) { + component.setConfiguration(new org.apache.camel.component.pgvector.PgVectorConfiguration()); + } + return component.getConfiguration(); + } + @Override + protected boolean setPropertyOnComponent( + Component component, + String name, + Object value) { + switch (name) { + case "configuration": ((PgVectorComponent) component).setConfiguration((org.apache.camel.component.pgvector.PgVectorConfiguration) value); return true; + case "dataSource": getOrCreateConfiguration((PgVectorComponent) component).setDataSource((javax.sql.DataSource) value); return true; + case "dimension": getOrCreateConfiguration((PgVectorComponent) component).setDimension((int) value); return true; + case "distanceType": getOrCreateConfiguration((PgVectorComponent) component).setDistanceType((java.lang.String) value); return true; + case "lazyStartProducer": ((PgVectorComponent) component).setLazyStartProducer((boolean) value); return true; + case "autowiredEnabled": ((PgVectorComponent) component).setAutowiredEnabled((boolean) value); return true; + default: return false; + } + } + } +} \ No newline at end of file diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java index 09654b6c8cea9..0b50eec3a2874 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilderFactory.java @@ -296,6 +296,7 @@ public interface EndpointBuilderFactory org.apache.camel.builder.endpoint.dsl.PdfEndpointBuilderFactory.PdfBuilders, org.apache.camel.builder.endpoint.dsl.PgEventEndpointBuilderFactory.PgEventBuilders, org.apache.camel.builder.endpoint.dsl.PgReplicationSlotEndpointBuilderFactory.PgReplicationSlotBuilders, + org.apache.camel.builder.endpoint.dsl.PgVectorEndpointBuilderFactory.PgVectorBuilders, org.apache.camel.builder.endpoint.dsl.PineconeVectorDbEndpointBuilderFactory.PineconeVectorDbBuilders, org.apache.camel.builder.endpoint.dsl.PlatformHttpEndpointBuilderFactory.PlatformHttpBuilders, org.apache.camel.builder.endpoint.dsl.Plc4XEndpointBuilderFactory.Plc4XBuilders, diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java index 6f423c2f75da4..a30690261df07 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointBuilders.java @@ -293,6 +293,7 @@ public interface EndpointBuilders org.apache.camel.builder.endpoint.dsl.PdfEndpointBuilderFactory, org.apache.camel.builder.endpoint.dsl.PgEventEndpointBuilderFactory, org.apache.camel.builder.endpoint.dsl.PgReplicationSlotEndpointBuilderFactory, + org.apache.camel.builder.endpoint.dsl.PgVectorEndpointBuilderFactory, org.apache.camel.builder.endpoint.dsl.PineconeVectorDbEndpointBuilderFactory, org.apache.camel.builder.endpoint.dsl.PlatformHttpEndpointBuilderFactory, org.apache.camel.builder.endpoint.dsl.Plc4XEndpointBuilderFactory, 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 408f13ccb8c84..1e804cae13f21 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 @@ -228,54 +228,6 @@ public static ArangoDbEndpointBuilderFactory.ArangoDbEndpointBuilder arangodb(St public static ArangoDbEndpointBuilderFactory.ArangoDbEndpointBuilder arangodb(String componentName, String path) { return ArangoDbEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * AS2 (camel-as2) - * Transfer data securely and reliably using the AS2 protocol (RFC4130). - * - * Category: file - * Since: 2.22 - * Maven coordinates: org.apache.camel:camel-as2 - * - * Syntax: as2:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 3 enums and the value can be one of: CLIENT, SERVER, RECEIPT - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param path apiName/methodName - * @return the dsl builder - */ - public static AS2EndpointBuilderFactory.AS2EndpointBuilder as2(String path) { - return as2("as2", path); - } - /** - * AS2 (camel-as2) - * Transfer data securely and reliably using the AS2 protocol (RFC4130). - * - * Category: file - * Since: 2.22 - * Maven coordinates: org.apache.camel:camel-as2 - * - * Syntax: as2:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 3 enums and the value can be one of: CLIENT, SERVER, RECEIPT - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path apiName/methodName - * @return the dsl builder - */ - public static AS2EndpointBuilderFactory.AS2EndpointBuilder as2(String componentName, String path) { - return AS2EndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * Asterisk (camel-asterisk) * Interact with Asterisk PBX Server (VoIP). @@ -396,66 +348,6 @@ public static AtomEndpointBuilderFactory.AtomEndpointBuilder atom(String path) { public static AtomEndpointBuilderFactory.AtomEndpointBuilder atom(String componentName, String path) { return AtomEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * Avro RPC (camel-avro-rpc) - * Produce or consume Apache Avro RPC services. - * - * Category: rpc - * Since: 2.10 - * Maven coordinates: org.apache.camel:camel-avro-rpc - * - * Syntax: avro:transport:host:port/messageName - * - * Path parameter: transport (required) - * Transport to use, can be either http or netty - * There are 2 enums and the value can be one of: http, netty - * - * Path parameter: port (required) - * Port number to use - * - * Path parameter: host (required) - * Hostname to use - * - * Path parameter: messageName - * The name of the message to send. - * - * @param path transport:host:port/messageName - * @return the dsl builder - */ - public static AvroEndpointBuilderFactory.AvroEndpointBuilder avro(String path) { - return avro("avro", path); - } - /** - * Avro RPC (camel-avro-rpc) - * Produce or consume Apache Avro RPC services. - * - * Category: rpc - * Since: 2.10 - * Maven coordinates: org.apache.camel:camel-avro-rpc - * - * Syntax: avro:transport:host:port/messageName - * - * Path parameter: transport (required) - * Transport to use, can be either http or netty - * There are 2 enums and the value can be one of: http, netty - * - * Path parameter: port (required) - * Port number to use - * - * Path parameter: host (required) - * Hostname to use - * - * Path parameter: messageName - * The name of the message to send. - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path transport:host:port/messageName - * @return the dsl builder - */ - public static AvroEndpointBuilderFactory.AvroEndpointBuilder avro(String componentName, String path) { - return AvroEndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * AWS Bedrock (camel-aws-bedrock) * Invoke Model of AWS Bedrock service. @@ -2506,58 +2398,6 @@ public static BonitaEndpointBuilderFactory.BonitaEndpointBuilder bonita(String p public static BonitaEndpointBuilderFactory.BonitaEndpointBuilder bonita(String componentName, String path) { return BonitaEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * Box (camel-box) - * Upload, download and manage files, folders, groups, collaborations, etc. - * on box.com. - * - * Category: cloud,file,api - * Since: 2.14 - * Maven coordinates: org.apache.camel:camel-box - * - * Syntax: box:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 10 enums and the value can be one of: COLLABORATIONS, COMMENTS, - * EVENT_LOGS, FILES, FOLDERS, GROUPS, EVENTS, SEARCH, TASKS, USERS - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param path apiName/methodName - * @return the dsl builder - */ - public static BoxEndpointBuilderFactory.BoxEndpointBuilder box(String path) { - return box("box", path); - } - /** - * Box (camel-box) - * Upload, download and manage files, folders, groups, collaborations, etc. - * on box.com. - * - * Category: cloud,file,api - * Since: 2.14 - * Maven coordinates: org.apache.camel:camel-box - * - * Syntax: box:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 10 enums and the value can be one of: COLLABORATIONS, COMMENTS, - * EVENT_LOGS, FILES, FOLDERS, GROUPS, EVENTS, SEARCH, TASKS, USERS - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path apiName/methodName - * @return the dsl builder - */ - public static BoxEndpointBuilderFactory.BoxEndpointBuilder box(String componentName, String path) { - return BoxEndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * Braintree (camel-braintree) * Process payments using Braintree Payments. @@ -4149,58 +3989,6 @@ public static DfdlEndpointBuilderFactory.DfdlEndpointBuilder dfdl(String path) { public static DfdlEndpointBuilderFactory.DfdlEndpointBuilder dfdl(String componentName, String path) { return DfdlEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * DHIS2 (camel-dhis2) - * Leverages the DHIS2 Java SDK to integrate Apache Camel with the DHIS2 Web - * API. - * - * Category: api - * Since: 4.0 - * Maven coordinates: org.apache.camel:camel-dhis2 - * - * Syntax: dhis2:apiName/methodName - * - * Path parameter: apiName (required) - * API operation (e.g., get) - * There are 5 enums and the value can be one of: POST, RESOURCE_TABLES, - * GET, DELETE, PUT - * - * Path parameter: methodName (required) - * Subject of the API operation (e.g., resource) - * - * @param path apiName/methodName - * @return the dsl builder - */ - public static Dhis2EndpointBuilderFactory.Dhis2EndpointBuilder dhis2(String path) { - return dhis2("dhis2", path); - } - /** - * DHIS2 (camel-dhis2) - * Leverages the DHIS2 Java SDK to integrate Apache Camel with the DHIS2 Web - * API. - * - * Category: api - * Since: 4.0 - * Maven coordinates: org.apache.camel:camel-dhis2 - * - * Syntax: dhis2:apiName/methodName - * - * Path parameter: apiName (required) - * API operation (e.g., get) - * There are 5 enums and the value can be one of: POST, RESOURCE_TABLES, - * GET, DELETE, PUT - * - * Path parameter: methodName (required) - * Subject of the API operation (e.g., resource) - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path apiName/methodName - * @return the dsl builder - */ - public static Dhis2EndpointBuilderFactory.Dhis2EndpointBuilder dhis2(String componentName, String path) { - return Dhis2EndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * DigitalOcean (camel-digitalocean) * Manage Droplets and resources within the DigitalOcean cloud. @@ -4959,60 +4747,6 @@ public static ExecEndpointBuilderFactory.ExecEndpointBuilder exec(String path) { public static ExecEndpointBuilderFactory.ExecEndpointBuilder exec(String componentName, String path) { return ExecEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * FHIR (camel-fhir) - * Exchange information in the healthcare domain using the FHIR (Fast - * Healthcare Interoperability Resources) standard. - * - * Category: api - * Since: 2.23 - * Maven coordinates: org.apache.camel:camel-fhir - * - * Syntax: fhir:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 13 enums and the value can be one of: CAPABILITIES, CREATE, - * DELETE, HISTORY, LOAD_PAGE, META, OPERATION, PATCH, READ, SEARCH, - * TRANSACTION, UPDATE, VALIDATE - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param path apiName/methodName - * @return the dsl builder - */ - public static FhirEndpointBuilderFactory.FhirEndpointBuilder fhir(String path) { - return fhir("fhir", path); - } - /** - * FHIR (camel-fhir) - * Exchange information in the healthcare domain using the FHIR (Fast - * Healthcare Interoperability Resources) standard. - * - * Category: api - * Since: 2.23 - * Maven coordinates: org.apache.camel:camel-fhir - * - * Syntax: fhir:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 13 enums and the value can be one of: CAPABILITIES, CREATE, - * DELETE, HISTORY, LOAD_PAGE, META, OPERATION, PATCH, READ, SEARCH, - * TRANSACTION, UPDATE, VALIDATE - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path apiName/methodName - * @return the dsl builder - */ - public static FhirEndpointBuilderFactory.FhirEndpointBuilder fhir(String componentName, String path) { - return FhirEndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * File (camel-file) * Read and write files. @@ -9638,54 +9372,6 @@ public static KeycloakEndpointBuilderFactory.KeycloakEndpointBuilder keycloak(St public static KeycloakEndpointBuilderFactory.KeycloakEndpointBuilder keycloak(String componentName, String path) { return KeycloakEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * Knative (camel-knative) - * Send and receive events from Knative. - * - * Category: cloud - * Since: 3.15 - * Maven coordinates: org.apache.camel:camel-knative - * - * Syntax: knative:type/typeId - * - * Path parameter: type - * The Knative resource type - * There are 3 enums and the value can be one of: endpoint, channel, event - * - * Path parameter: typeId - * The identifier of the Knative resource - * - * @param path type/typeId - * @return the dsl builder - */ - public static KnativeEndpointBuilderFactory.KnativeEndpointBuilder knative(String path) { - return knative("knative", path); - } - /** - * Knative (camel-knative) - * Send and receive events from Knative. - * - * Category: cloud - * Since: 3.15 - * Maven coordinates: org.apache.camel:camel-knative - * - * Syntax: knative:type/typeId - * - * Path parameter: type - * The Knative resource type - * There are 3 enums and the value can be one of: endpoint, channel, event - * - * Path parameter: typeId - * The identifier of the Knative resource - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path type/typeId - * @return the dsl builder - */ - public static KnativeEndpointBuilderFactory.KnativeEndpointBuilder knative(String componentName, String path) { - return KnativeEndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * KServe (camel-kserve) * Provide access to AI model servers with the KServe standard to run @@ -12354,106 +12040,6 @@ public static OAIPMHEndpointBuilderFactory.OAIPMHEndpointBuilder oaipmh(String p public static OAIPMHEndpointBuilderFactory.OAIPMHEndpointBuilder oaipmh(String componentName, String path) { return OAIPMHEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * Olingo2 (camel-olingo2) - * Communicate with OData 2.0 services using Apache Olingo. - * - * Category: cloud - * Since: 2.14 - * Maven coordinates: org.apache.camel:camel-olingo2 - * - * Syntax: olingo2:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 1 enums and the value can be one of: DEFAULT - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param path apiName/methodName - * @return the dsl builder - */ - @Deprecated - public static Olingo2EndpointBuilderFactory.Olingo2EndpointBuilder olingo2(String path) { - return olingo2("olingo2", path); - } - /** - * Olingo2 (camel-olingo2) - * Communicate with OData 2.0 services using Apache Olingo. - * - * Category: cloud - * Since: 2.14 - * Maven coordinates: org.apache.camel:camel-olingo2 - * - * Syntax: olingo2:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 1 enums and the value can be one of: DEFAULT - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path apiName/methodName - * @return the dsl builder - */ - @Deprecated - public static Olingo2EndpointBuilderFactory.Olingo2EndpointBuilder olingo2(String componentName, String path) { - return Olingo2EndpointBuilderFactory.endpointBuilder(componentName, path); - } - /** - * Olingo4 (camel-olingo4) - * Communicate with OData 4.0 services using Apache Olingo OData API. - * - * Category: cloud - * Since: 2.19 - * Maven coordinates: org.apache.camel:camel-olingo4 - * - * Syntax: olingo4:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 1 enums and the value can be one of: DEFAULT - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param path apiName/methodName - * @return the dsl builder - */ - @Deprecated - public static Olingo4EndpointBuilderFactory.Olingo4EndpointBuilder olingo4(String path) { - return olingo4("olingo4", path); - } - /** - * Olingo4 (camel-olingo4) - * Communicate with OData 4.0 services using Apache Olingo OData API. - * - * Category: cloud - * Since: 2.19 - * Maven coordinates: org.apache.camel:camel-olingo4 - * - * Syntax: olingo4:apiName/methodName - * - * Path parameter: apiName (required) - * What kind of operation to perform - * There are 1 enums and the value can be one of: DEFAULT - * - * Path parameter: methodName (required) - * What sub operation to use for the selected operation - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path apiName/methodName - * @return the dsl builder - */ - @Deprecated - public static Olingo4EndpointBuilderFactory.Olingo4EndpointBuilder olingo4(String componentName, String path) { - return Olingo4EndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * Once (camel-once) * Trigger a single message only once at startup (useful for development and @@ -13322,6 +12908,46 @@ public static PgEventEndpointBuilderFactory.PgEventEndpointBuilder pgevent(Strin public static PgEventEndpointBuilderFactory.PgEventEndpointBuilder pgevent(String componentName, String path) { return PgEventEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * PGVector (camel-pgvector) + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Category: database,ai + * Since: 4.19 + * Maven coordinates: org.apache.camel:camel-pgvector + * + * Syntax: pgvector:collection + * + * Path parameter: collection (required) + * The collection (table) name + * + * @param path collection + * @return the dsl builder + */ + public static PgVectorEndpointBuilderFactory.PgVectorEndpointBuilder pgvector(String path) { + return pgvector("pgvector", path); + } + /** + * PGVector (camel-pgvector) + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Category: database,ai + * Since: 4.19 + * Maven coordinates: org.apache.camel:camel-pgvector + * + * Syntax: pgvector:collection + * + * Path parameter: collection (required) + * The collection (table) name + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path collection + * @return the dsl builder + */ + public static PgVectorEndpointBuilderFactory.PgVectorEndpointBuilder pgvector(String componentName, String path) { + return PgVectorEndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * Pinecone (camel-pinecone) * Perform operations on the Pinecone Vector Database. @@ -13966,7 +13592,7 @@ public static RestApiEndpointBuilderFactory.RestApiEndpointBuilder restApi(Strin } /** * REST OpenApi (camel-rest-openapi) - * To call and expose REST services using OpenAPI specification as contract. + * To call REST services using OpenAPI specification as contract. * * Category: rest,api * Since: 3.1 @@ -14003,7 +13629,7 @@ public static RestOpenApiEndpointBuilderFactory.RestOpenApiEndpointBuilder restO } /** * REST OpenApi (camel-rest-openapi) - * To call and expose REST services using OpenAPI specification as contract. + * To call REST services using OpenAPI specification as contract. * * Category: rest,api * Since: 3.1 @@ -14214,88 +13840,6 @@ public static SagaEndpointBuilderFactory.SagaEndpointBuilder saga(String path) { public static SagaEndpointBuilderFactory.SagaEndpointBuilder saga(String componentName, String path) { return SagaEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * Salesforce (camel-salesforce) - * Communicate with Salesforce using Java DTOs. - * - * Category: cloud,saas - * Since: 2.12 - * Maven coordinates: org.apache.camel:camel-salesforce - * - * Syntax: salesforce:operationName:topicName - * - * Path parameter: operationName (required) - * The operation to use - * There are 69 enums and the value can be one of: getVersions, - * getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, - * createSObject, updateSObject, deleteSObject, getSObjectWithId, - * upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, - * queryAll, search, apexCall, recent, getEventSchema, createJob, getJob, - * closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, - * getResults, createBatchQuery, getQueryResultIds, getQueryResult, - * getRecentReports, getReportDescription, executeSyncReport, - * executeAsyncReport, getReportInstances, getReportResults, limits, - * approval, approvals, composite-tree, composite-batch, composite, - * compositeRetrieveSObjectCollections, compositeCreateSObjectCollections, - * compositeUpdateSObjectCollections, compositeUpsertSObjectCollections, - * compositeDeleteSObjectCollections, bulk2GetAllJobs, bulk2CreateJob, - * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob, - * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults, - * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob, - * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob, - * bulk2DeleteQueryJob, raw, subscribe, pubSubSubscribe, pubSubPublish - * - * Path parameter: topicName - * The name of the topic/channel to use - * - * @param path operationName:topicName - * @return the dsl builder - */ - public static SalesforceEndpointBuilderFactory.SalesforceEndpointBuilder salesforce(String path) { - return salesforce("salesforce", path); - } - /** - * Salesforce (camel-salesforce) - * Communicate with Salesforce using Java DTOs. - * - * Category: cloud,saas - * Since: 2.12 - * Maven coordinates: org.apache.camel:camel-salesforce - * - * Syntax: salesforce:operationName:topicName - * - * Path parameter: operationName (required) - * The operation to use - * There are 69 enums and the value can be one of: getVersions, - * getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, - * createSObject, updateSObject, deleteSObject, getSObjectWithId, - * upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, - * queryAll, search, apexCall, recent, getEventSchema, createJob, getJob, - * closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, - * getResults, createBatchQuery, getQueryResultIds, getQueryResult, - * getRecentReports, getReportDescription, executeSyncReport, - * executeAsyncReport, getReportInstances, getReportResults, limits, - * approval, approvals, composite-tree, composite-batch, composite, - * compositeRetrieveSObjectCollections, compositeCreateSObjectCollections, - * compositeUpdateSObjectCollections, compositeUpsertSObjectCollections, - * compositeDeleteSObjectCollections, bulk2GetAllJobs, bulk2CreateJob, - * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob, - * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults, - * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob, - * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob, - * bulk2DeleteQueryJob, raw, subscribe, pubSubSubscribe, pubSubPublish - * - * Path parameter: topicName - * The name of the topic/channel to use - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path operationName:topicName - * @return the dsl builder - */ - public static SalesforceEndpointBuilderFactory.SalesforceEndpointBuilder salesforce(String componentName, String path) { - return SalesforceEndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * SAP NetWeaver (camel-sap-netweaver) * Send requests to SAP NetWeaver Gateway using HTTP. @@ -14518,46 +14062,6 @@ public static SedaEndpointBuilderFactory.SedaEndpointBuilder seda(String path) { public static SedaEndpointBuilderFactory.SedaEndpointBuilder seda(String componentName, String path) { return SedaEndpointBuilderFactory.endpointBuilder(componentName, path); } - /** - * ServiceNow (camel-servicenow) - * Interact with ServiceNow via its REST API. - * - * Category: api,cloud,management - * Since: 2.18 - * Maven coordinates: org.apache.camel:camel-servicenow - * - * Syntax: servicenow:instanceName - * - * Path parameter: instanceName (required) - * The ServiceNow instance name - * - * @param path instanceName - * @return the dsl builder - */ - public static ServiceNowEndpointBuilderFactory.ServiceNowEndpointBuilder servicenow(String path) { - return servicenow("servicenow", path); - } - /** - * ServiceNow (camel-servicenow) - * Interact with ServiceNow via its REST API. - * - * Category: api,cloud,management - * Since: 2.18 - * Maven coordinates: org.apache.camel:camel-servicenow - * - * Syntax: servicenow:instanceName - * - * Path parameter: instanceName (required) - * The ServiceNow instance name - * - * @param componentName to use a custom component name for the endpoint - * instead of the default name - * @param path instanceName - * @return the dsl builder - */ - public static ServiceNowEndpointBuilderFactory.ServiceNowEndpointBuilder servicenow(String componentName, String path) { - return ServiceNowEndpointBuilderFactory.endpointBuilder(componentName, path); - } /** * Servlet (camel-servlet) * Serve HTTP requests by a Servlet. diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java new file mode 100644 index 0000000000000..fc7c51f279385 --- /dev/null +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java @@ -0,0 +1,319 @@ +/* Generated by camel build tools - do NOT edit this file! */ +/* + * 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.builder.endpoint.dsl; + +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.stream.*; +import javax.annotation.processing.Generated; +import org.apache.camel.builder.EndpointConsumerBuilder; +import org.apache.camel.builder.EndpointProducerBuilder; +import org.apache.camel.builder.endpoint.AbstractEndpointBuilder; + +/** + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointDslMojo") +public interface PgVectorEndpointBuilderFactory { + + /** + * Builder for endpoint for the PGVector component. + */ + public interface PgVectorEndpointBuilder + extends + EndpointProducerBuilder { + default AdvancedPgVectorEndpointBuilder advanced() { + return (AdvancedPgVectorEndpointBuilder) this; + } + + /** + * The DataSource to use for connecting to the PostgreSQL database with + * pgvector extension. + * + * The option is a: javax.sql.DataSource type. + * + * Group: producer + * + * @param dataSource the value to set + * @return the dsl builder + */ + default PgVectorEndpointBuilder dataSource(javax.sql.DataSource dataSource) { + doSetProperty("dataSource", dataSource); + return this; + } + /** + * The DataSource to use for connecting to the PostgreSQL database with + * pgvector extension. + * + * The option will be converted to a javax.sql.DataSource + * type. + * + * Group: producer + * + * @param dataSource the value to set + * @return the dsl builder + */ + default PgVectorEndpointBuilder dataSource(String dataSource) { + doSetProperty("dataSource", dataSource); + return this; + } + /** + * The dimension of the vectors to store. + * + * The option is a: int type. + * + * Default: 384 + * Group: producer + * + * @param dimension the value to set + * @return the dsl builder + */ + default PgVectorEndpointBuilder dimension(int dimension) { + doSetProperty("dimension", dimension); + return this; + } + /** + * The dimension of the vectors to store. + * + * The option will be converted to a int type. + * + * Default: 384 + * Group: producer + * + * @param dimension the value to set + * @return the dsl builder + */ + default PgVectorEndpointBuilder dimension(String dimension) { + doSetProperty("dimension", dimension); + return this; + } + /** + * The distance type to use for similarity search. + * + * The option is a: java.lang.String type. + * + * Default: cosine + * Group: producer + * + * @param distanceType the value to set + * @return the dsl builder + */ + default PgVectorEndpointBuilder distanceType(String distanceType) { + doSetProperty("distanceType", distanceType); + return this; + } + } + + /** + * Advanced builder for endpoint for the PGVector component. + */ + public interface AdvancedPgVectorEndpointBuilder + extends + EndpointProducerBuilder { + default PgVectorEndpointBuilder basic() { + return (PgVectorEndpointBuilder) this; + } + + /** + * 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 producer may otherwise fail during + * starting and cause the route to fail being started. By deferring this + * startup to be lazy then the startup failure can be handled during + * routing messages via Camel's routing error handlers. Beware that when + * the first message is processed then creating and starting the + * producer may take a little time and prolong the total processing time + * of the processing. + * + * The option is a: boolean type. + * + * Default: false + * Group: producer (advanced) + * + * @param lazyStartProducer the value to set + * @return the dsl builder + */ + default AdvancedPgVectorEndpointBuilder lazyStartProducer(boolean lazyStartProducer) { + doSetProperty("lazyStartProducer", lazyStartProducer); + return this; + } + /** + * 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 producer may otherwise fail during + * starting and cause the route to fail being started. By deferring this + * startup to be lazy then the startup failure can be handled during + * routing messages via Camel's routing error handlers. Beware that when + * the first message is processed then creating and starting the + * producer may take a little time and prolong the total processing time + * of the processing. + * + * The option will be converted to a boolean type. + * + * Default: false + * Group: producer (advanced) + * + * @param lazyStartProducer the value to set + * @return the dsl builder + */ + default AdvancedPgVectorEndpointBuilder lazyStartProducer(String lazyStartProducer) { + doSetProperty("lazyStartProducer", lazyStartProducer); + return this; + } + } + + public interface PgVectorBuilders { + /** + * PGVector (camel-pgvector) + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Category: database,ai + * Since: 4.19 + * Maven coordinates: org.apache.camel:camel-pgvector + * + * @return the dsl builder for the headers' name. + */ + default PgVectorHeaderNameBuilder pgvector() { + return PgVectorHeaderNameBuilder.INSTANCE; + } + /** + * PGVector (camel-pgvector) + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Category: database,ai + * Since: 4.19 + * Maven coordinates: org.apache.camel:camel-pgvector + * + * Syntax: pgvector:collection + * + * Path parameter: collection (required) + * The collection (table) name + * + * @param path collection + * @return the dsl builder + */ + default PgVectorEndpointBuilder pgvector(String path) { + return PgVectorEndpointBuilderFactory.endpointBuilder("pgvector", path); + } + /** + * PGVector (camel-pgvector) + * Perform operations on the PostgreSQL pgvector Vector Database. + * + * Category: database,ai + * Since: 4.19 + * Maven coordinates: org.apache.camel:camel-pgvector + * + * Syntax: pgvector:collection + * + * Path parameter: collection (required) + * The collection (table) name + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path collection + * @return the dsl builder + */ + default PgVectorEndpointBuilder pgvector(String componentName, String path) { + return PgVectorEndpointBuilderFactory.endpointBuilder(componentName, path); + } + + } + /** + * The builder of headers' name for the PGVector component. + */ + public static class PgVectorHeaderNameBuilder { + /** + * The internal instance of the builder used to access to all the + * methods representing the name of headers. + */ + private static final PgVectorHeaderNameBuilder INSTANCE = new PgVectorHeaderNameBuilder(); + + /** + * The action to be performed. + * + * The option is a: {@code String} type. + * + * Group: producer + * + * @return the name of the header {@code PgVectorAction}. + */ + public String pgVectorAction() { + return "CamelPgVectorAction"; + } + /** + * The id of the vector record. + * + * The option is a: {@code String} type. + * + * Group: producer + * + * @return the name of the header {@code PgVectorRecordId}. + */ + public String pgVectorRecordId() { + return "CamelPgVectorRecordId"; + } + /** + * The maximum number of results to return for similarity search. + * + * The option is a: {@code Integer} type. + * + * Default: 3 + * Group: producer + * + * @return the name of the header {@code PgVectorQueryTopK}. + */ + public String pgVectorQueryTopK() { + return "CamelPgVectorQueryTopK"; + } + /** + * The text content to store alongside the vector embedding. + * + * The option is a: {@code String} type. + * + * Group: producer + * + * @return the name of the header {@code PgVectorTextContent}. + */ + public String pgVectorTextContent() { + return "CamelPgVectorTextContent"; + } + /** + * The metadata associated with the vector record, stored as JSON. + * + * The option is a: {@code String} type. + * + * Group: producer + * + * @return the name of the header {@code PgVectorMetadata}. + */ + public String pgVectorMetadata() { + return "CamelPgVectorMetadata"; + } + } + static PgVectorEndpointBuilder endpointBuilder(String componentName, String path) { + class PgVectorEndpointBuilderImpl extends AbstractEndpointBuilder implements PgVectorEndpointBuilder, AdvancedPgVectorEndpointBuilder { + public PgVectorEndpointBuilderImpl(String path) { + super(componentName, path); + } + } + return new PgVectorEndpointBuilderImpl(path); + } +} \ No newline at end of file diff --git a/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties b/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties index e20ed4f61f3ad..aaf1a111c3470 100644 --- a/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties +++ b/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties @@ -305,6 +305,7 @@ org.apache.camel.component.paho.mqtt5.PahoMqtt5Component=camel:paho-mqtt5 org.apache.camel.component.pdf.PdfComponent=camel:pdf org.apache.camel.component.pg.replication.slot.PgReplicationSlotComponent=camel:pg-replication-slot org.apache.camel.component.pgevent.PgEventComponent=camel:pgevent +org.apache.camel.component.pgvector.PgVectorComponent=camel:pgvector org.apache.camel.component.pinecone.PineconeVectorDbComponent=camel:pinecone org.apache.camel.component.platform.http.PlatformHttpComponent=camel:platform-http org.apache.camel.component.plc4x.Plc4XComponent=camel:plc4x From 2193ff7edbc2a153876bacc9f7b7ed060b0315ad Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Mar 2026 22:33:23 +0100 Subject: [PATCH 03/20] CAMEL-21540: Add generated files and fix docs for PGVector component - Add BOM, catalog, DSL, and documentation generated files - Remove Spring Boot starter reference (no starter yet) Co-Authored-By: Claude Opus 4.6 --- .../camel-pgvector/src/main/docs/pgvector-component.adoc | 4 ---- docs/components/modules/ROOT/pages/pgvector-component.adoc | 4 ---- 2 files changed, 8 deletions(-) diff --git a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc index 6d2dca26aa999..7470e9dd47f2f 100644 --- a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc +++ b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc @@ -9,7 +9,6 @@ :component-header: Only producer is supported //Manually maintained attributes :group: AI -:camel-spring-boot-name: pgvector *Since Camel {since}* @@ -55,6 +54,3 @@ include::partial$component-configure-options.adoc[] include::partial$component-endpoint-options.adoc[] include::partial$component-endpoint-headers.adoc[] // component options: END - - -include::spring-boot:partial$starter.adoc[] diff --git a/docs/components/modules/ROOT/pages/pgvector-component.adoc b/docs/components/modules/ROOT/pages/pgvector-component.adoc index 6d2dca26aa999..7470e9dd47f2f 100644 --- a/docs/components/modules/ROOT/pages/pgvector-component.adoc +++ b/docs/components/modules/ROOT/pages/pgvector-component.adoc @@ -9,7 +9,6 @@ :component-header: Only producer is supported //Manually maintained attributes :group: AI -:camel-spring-boot-name: pgvector *Since Camel {since}* @@ -55,6 +54,3 @@ include::partial$component-configure-options.adoc[] include::partial$component-endpoint-options.adoc[] include::partial$component-endpoint-headers.adoc[] // component options: END - - -include::spring-boot:partial$starter.adoc[] From 7a601c4daeb06e1520208577d47964ef6776df68 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Mar 2026 23:11:26 +0100 Subject: [PATCH 04/20] CAMEL-21540: Fix docs symlinks and nav ordering for pgvector component Co-Authored-By: Claude Opus 4.6 --- .../modules/ROOT/examples/json/pgvector.json | 49 +--------------- docs/components/modules/ROOT/nav.adoc | 2 +- .../ROOT/pages/pgvector-component.adoc | 57 +------------------ 3 files changed, 3 insertions(+), 105 deletions(-) mode change 100644 => 120000 docs/components/modules/ROOT/examples/json/pgvector.json mode change 100644 => 120000 docs/components/modules/ROOT/pages/pgvector-component.adoc diff --git a/docs/components/modules/ROOT/examples/json/pgvector.json b/docs/components/modules/ROOT/examples/json/pgvector.json deleted file mode 100644 index 69d46599f91e7..0000000000000 --- a/docs/components/modules/ROOT/examples/json/pgvector.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "component": { - "kind": "component", - "name": "pgvector", - "title": "PGVector", - "description": "Perform operations on the PostgreSQL pgvector Vector Database.", - "deprecated": false, - "firstVersion": "4.19.0", - "label": "database,ai", - "javaType": "org.apache.camel.component.pgvector.PgVectorComponent", - "supportLevel": "Preview", - "groupId": "org.apache.camel", - "artifactId": "camel-pgvector", - "version": "4.19.0-SNAPSHOT", - "scheme": "pgvector", - "extendsScheme": "", - "syntax": "pgvector:collection", - "async": false, - "api": false, - "consumerOnly": false, - "producerOnly": true, - "lenientProperties": false, - "browsable": false, - "remote": true - }, - "componentProperties": { - "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.pgvector.PgVectorConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The configuration;" }, - "dataSource": { "index": 1, "kind": "property", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, - "dimension": { "index": 2, "kind": "property", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, - "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, - "lazyStartProducer": { "index": 4, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } - }, - "headers": { - "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, - "CamelPgVectorRecordId": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id of the vector record.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#RECORD_ID" }, - "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, - "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, - "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" } - }, - "properties": { - "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, - "dataSource": { "index": 1, "kind": "parameter", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, - "dimension": { "index": 2, "kind": "parameter", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, - "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, - "lazyStartProducer": { "index": 4, "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." } - } -} diff --git a/docs/components/modules/ROOT/examples/json/pgvector.json b/docs/components/modules/ROOT/examples/json/pgvector.json new file mode 120000 index 0000000000000..44847d9815ea6 --- /dev/null +++ b/docs/components/modules/ROOT/examples/json/pgvector.json @@ -0,0 +1 @@ +../../../../../../components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json \ No newline at end of file diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc index aa815ab07e081..e525948fb1d49 100644 --- a/docs/components/modules/ROOT/nav.adoc +++ b/docs/components/modules/ROOT/nav.adoc @@ -313,9 +313,9 @@ ** xref:paho-component.adoc[Paho] ** xref:paho-mqtt5-component.adoc[Paho MQTT 5] ** xref:pdf-component.adoc[PDF] +** xref:pgvector-component.adoc[PGVector] ** xref:platform-http-component.adoc[Platform HTTP] ** xref:plc4x-component.adoc[PLC4X] -** xref:pgvector-component.adoc[PGVector] ** xref:pgevent-component.adoc[PostgresSQL Event] ** xref:pg-replication-slot-component.adoc[PostgresSQL Replication Slot] ** xref:pqc-component.adoc[PQC Algorithms] diff --git a/docs/components/modules/ROOT/pages/pgvector-component.adoc b/docs/components/modules/ROOT/pages/pgvector-component.adoc deleted file mode 100644 index 7470e9dd47f2f..0000000000000 --- a/docs/components/modules/ROOT/pages/pgvector-component.adoc +++ /dev/null @@ -1,56 +0,0 @@ -= PGVector Component -:doctitle: PGVector -:shortname: pgvector -:artifactid: camel-pgvector -:description: Perform operations on the PostgreSQL pgvector Vector Database. -:since: 4.19 -:supportlevel: Preview -:tabs-sync-option: -:component-header: Only producer is supported -//Manually maintained attributes -:group: AI - -*Since Camel {since}* - -*{component-header}* - -The PGVector Component provides support for interacting with https://github.com/pgvector/pgvector[pgvector], -the open-source vector similarity search extension for PostgreSQL. - -== URI format - ----- -pgvector:collection[?options] ----- - -Where *collection* represents the table name used to store vectors in the PostgreSQL database. - -== Configuring the DataSource - -A `javax.sql.DataSource` must be provided. It is recommended to use a connection pooling DataSource -(such as HikariCP) for production deployments. The DataSource can be set on the component or endpoint -configuration, or autowired from the registry. - -== Actions - -The following actions are supported via the `CamelPgVectorAction` header: - -- `CREATE_TABLE` - Creates the pgvector extension and a table with columns: id, text_content, metadata, embedding -- `DROP_TABLE` - Drops the table -- `UPSERT` - Inserts or updates a vector record. The body must be a `List`. Set `CamelPgVectorRecordId` for the ID (auto-generated UUID if not set), `CamelPgVectorTextContent` for text, and `CamelPgVectorMetadata` for metadata -- `DELETE` - Deletes a record by `CamelPgVectorRecordId` -- `SIMILARITY_SEARCH` - Searches for similar vectors. The body must be a `List` query vector. Set `CamelPgVectorQueryTopK` for max results (default 3). Returns a `List>` with keys: id, text_content, metadata, distance - -== LangChain4j Integration - -This component provides data type transformers for LangChain4j integration: - -- `pgvector:embeddings` - Transforms LangChain4j embedding output into a format suitable for the PGVector UPSERT action -- `pgvector:rag` - Transforms similarity search results into a `List` for RAG pipelines - - -// component options: START -include::partial$component-configure-options.adoc[] -include::partial$component-endpoint-options.adoc[] -include::partial$component-endpoint-headers.adoc[] -// component options: END diff --git a/docs/components/modules/ROOT/pages/pgvector-component.adoc b/docs/components/modules/ROOT/pages/pgvector-component.adoc new file mode 120000 index 0000000000000..62dcbff37d4ed --- /dev/null +++ b/docs/components/modules/ROOT/pages/pgvector-component.adoc @@ -0,0 +1 @@ +../../../../../components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc \ No newline at end of file From d8e0eaa1d7bbbbb76336a1e2ebb7e9ebe651ecd6 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 23 Mar 2026 23:39:45 +0100 Subject: [PATCH 05/20] CAMEL-21540: Fix generated files - restore missing components from main and add pgvector entries Co-Authored-By: Claude Opus 4.6 --- .../camel/catalog/components.properties | 10 + .../apache/camel/main/components.properties | 10 + .../component/ComponentsBuilderFactory.java | 137 ++++- .../endpoint/StaticEndpointBuilders.java | 564 +++++++++++++++++- 4 files changed, 702 insertions(+), 19 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties index 5d09357914ed4..6d730df36b5ac 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties @@ -2,9 +2,11 @@ activemq activemq6 amqp arangodb +as2 asterisk atmosphere-websocket atom +avro aws-bedrock aws-bedrock-agent aws-bedrock-agent-runtime @@ -54,6 +56,7 @@ azure-storage-queue bean bean-validator bonita +box braintree browse caffeine-cache @@ -90,6 +93,7 @@ debezium-oracle debezium-postgres debezium-sqlserver dfdl +dhis2 digitalocean direct disruptor @@ -107,6 +111,7 @@ elasticsearch elasticsearch-rest-client event exec +fhir file file-watch flatpack @@ -212,6 +217,7 @@ jte kafka kamelet keycloak +knative kserve kubernetes-config-maps kubernetes-cronjob @@ -268,6 +274,8 @@ neo4j netty netty-http oaipmh +olingo2 +olingo4 once openai opensearch @@ -308,11 +316,13 @@ robotframework rocketmq rss saga +salesforce sap-netweaver scheduler schematron scp seda +servicenow servlet sftp sjms diff --git a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties index 5d09357914ed4..6d730df36b5ac 100644 --- a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties +++ b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties @@ -2,9 +2,11 @@ activemq activemq6 amqp arangodb +as2 asterisk atmosphere-websocket atom +avro aws-bedrock aws-bedrock-agent aws-bedrock-agent-runtime @@ -54,6 +56,7 @@ azure-storage-queue bean bean-validator bonita +box braintree browse caffeine-cache @@ -90,6 +93,7 @@ debezium-oracle debezium-postgres debezium-sqlserver dfdl +dhis2 digitalocean direct disruptor @@ -107,6 +111,7 @@ elasticsearch elasticsearch-rest-client event exec +fhir file file-watch flatpack @@ -212,6 +217,7 @@ jte kafka kamelet keycloak +knative kserve kubernetes-config-maps kubernetes-cronjob @@ -268,6 +274,8 @@ neo4j netty netty-http oaipmh +olingo2 +olingo4 once openai opensearch @@ -308,11 +316,13 @@ robotframework rocketmq rss saga +salesforce sap-netweaver scheduler schematron scp seda +servicenow servlet sftp sjms 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 3e5b62df1f47a..e57b1c8455a7c 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 @@ -100,6 +100,19 @@ static AmqpComponentBuilderFactory.AmqpComponentBuilder amqp() { static ArangodbComponentBuilderFactory.ArangodbComponentBuilder arangodb() { return ArangodbComponentBuilderFactory.arangodb(); } + /** + * AS2 (camel-as2) + * Transfer data securely and reliably using the AS2 protocol (RFC4130). + * + * Category: file + * Since: 2.22 + * Maven coordinates: org.apache.camel:camel-as2 + * + * @return the dsl builder + */ + static As2ComponentBuilderFactory.As2ComponentBuilder as2() { + return As2ComponentBuilderFactory.as2(); + } /** * Asterisk (camel-asterisk) * Interact with Asterisk PBX Server (VoIP). @@ -139,6 +152,19 @@ static AtmosphereWebsocketComponentBuilderFactory.AtmosphereWebsocketComponentBu static AtomComponentBuilderFactory.AtomComponentBuilder atom() { return AtomComponentBuilderFactory.atom(); } + /** + * Avro RPC (camel-avro-rpc) + * Produce or consume Apache Avro RPC services. + * + * Category: rpc + * Since: 2.10 + * Maven coordinates: org.apache.camel:camel-avro-rpc + * + * @return the dsl builder + */ + static AvroComponentBuilderFactory.AvroComponentBuilder avro() { + return AvroComponentBuilderFactory.avro(); + } /** * AWS Bedrock (camel-aws-bedrock) * Invoke Model of AWS Bedrock service. @@ -781,6 +807,20 @@ static BeanValidatorComponentBuilderFactory.BeanValidatorComponentBuilder beanVa static BonitaComponentBuilderFactory.BonitaComponentBuilder bonita() { return BonitaComponentBuilderFactory.bonita(); } + /** + * Box (camel-box) + * Upload, download and manage files, folders, groups, collaborations, etc. + * on box.com. + * + * Category: cloud,file,api + * Since: 2.14 + * Maven coordinates: org.apache.camel:camel-box + * + * @return the dsl builder + */ + static BoxComponentBuilderFactory.BoxComponentBuilder box() { + return BoxComponentBuilderFactory.box(); + } /** * Braintree (camel-braintree) * Process payments using Braintree Payments. @@ -1267,6 +1307,20 @@ static DebeziumSqlserverComponentBuilderFactory.DebeziumSqlserverComponentBuilde static DfdlComponentBuilderFactory.DfdlComponentBuilder dfdl() { return DfdlComponentBuilderFactory.dfdl(); } + /** + * DHIS2 (camel-dhis2) + * Leverages the DHIS2 Java SDK to integrate Apache Camel with the DHIS2 Web + * API. + * + * Category: api + * Since: 4.0 + * Maven coordinates: org.apache.camel:camel-dhis2 + * + * @return the dsl builder + */ + static Dhis2ComponentBuilderFactory.Dhis2ComponentBuilder dhis2() { + return Dhis2ComponentBuilderFactory.dhis2(); + } /** * DigitalOcean (camel-digitalocean) * Manage Droplets and resources within the DigitalOcean cloud. @@ -1495,6 +1549,20 @@ static EventComponentBuilderFactory.EventComponentBuilder event() { static ExecComponentBuilderFactory.ExecComponentBuilder exec() { return ExecComponentBuilderFactory.exec(); } + /** + * FHIR (camel-fhir) + * Exchange information in the healthcare domain using the FHIR (Fast + * Healthcare Interoperability Resources) standard. + * + * Category: api + * Since: 2.23 + * Maven coordinates: org.apache.camel:camel-fhir + * + * @return the dsl builder + */ + static FhirComponentBuilderFactory.FhirComponentBuilder fhir() { + return FhirComponentBuilderFactory.fhir(); + } /** * File (camel-file) * Read and write files. @@ -2888,6 +2956,19 @@ static KameletComponentBuilderFactory.KameletComponentBuilder kamelet() { static KeycloakComponentBuilderFactory.KeycloakComponentBuilder keycloak() { return KeycloakComponentBuilderFactory.keycloak(); } + /** + * Knative (camel-knative) + * Send and receive events from Knative. + * + * Category: cloud + * Since: 3.15 + * Maven coordinates: org.apache.camel:camel-knative + * + * @return the dsl builder + */ + static KnativeComponentBuilderFactory.KnativeComponentBuilder knative() { + return KnativeComponentBuilderFactory.knative(); + } /** * KServe (camel-kserve) * Provide access to AI model servers with the KServe standard to run @@ -3636,6 +3717,32 @@ static NettyHttpComponentBuilderFactory.NettyHttpComponentBuilder nettyHttp() { static OaipmhComponentBuilderFactory.OaipmhComponentBuilder oaipmh() { return OaipmhComponentBuilderFactory.oaipmh(); } + /** + * Olingo2 (camel-olingo2) + * Communicate with OData 2.0 services using Apache Olingo. + * + * Category: cloud + * Since: 2.14 + * Maven coordinates: org.apache.camel:camel-olingo2 + * + * @return the dsl builder + */ + static Olingo2ComponentBuilderFactory.Olingo2ComponentBuilder olingo2() { + return Olingo2ComponentBuilderFactory.olingo2(); + } + /** + * Olingo4 (camel-olingo4) + * Communicate with OData 4.0 services using Apache Olingo OData API. + * + * Category: cloud + * Since: 2.19 + * Maven coordinates: org.apache.camel:camel-olingo4 + * + * @return the dsl builder + */ + static Olingo4ComponentBuilderFactory.Olingo4ComponentBuilder olingo4() { + return Olingo4ComponentBuilderFactory.olingo4(); + } /** * Once (camel-once) * Trigger a single message only once at startup (useful for development and @@ -3890,11 +3997,11 @@ static PgeventComponentBuilderFactory.PgeventComponentBuilder pgevent() { /** * PGVector (camel-pgvector) * Perform operations on the PostgreSQL pgvector Vector Database. - * + * * Category: database,ai * Since: 4.19 * Maven coordinates: org.apache.camel:camel-pgvector - * + * * @return the dsl builder */ static PgvectorComponentBuilderFactory.PgvectorComponentBuilder pgvector() { @@ -4166,6 +4273,19 @@ static RssComponentBuilderFactory.RssComponentBuilder rss() { static SagaComponentBuilderFactory.SagaComponentBuilder saga() { return SagaComponentBuilderFactory.saga(); } + /** + * Salesforce (camel-salesforce) + * Communicate with Salesforce using Java DTOs. + * + * Category: cloud,saas + * Since: 2.12 + * Maven coordinates: org.apache.camel:camel-salesforce + * + * @return the dsl builder + */ + static SalesforceComponentBuilderFactory.SalesforceComponentBuilder salesforce() { + return SalesforceComponentBuilderFactory.salesforce(); + } /** * SAP NetWeaver (camel-sap-netweaver) * Send requests to SAP NetWeaver Gateway using HTTP. @@ -4233,6 +4353,19 @@ static ScpComponentBuilderFactory.ScpComponentBuilder scp() { static SedaComponentBuilderFactory.SedaComponentBuilder seda() { return SedaComponentBuilderFactory.seda(); } + /** + * ServiceNow (camel-servicenow) + * Interact with ServiceNow via its REST API. + * + * Category: api,cloud,management + * Since: 2.18 + * Maven coordinates: org.apache.camel:camel-servicenow + * + * @return the dsl builder + */ + static ServicenowComponentBuilderFactory.ServicenowComponentBuilder servicenow() { + return ServicenowComponentBuilderFactory.servicenow(); + } /** * Servlet (camel-servlet) * Serve HTTP requests by a Servlet. 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 1e804cae13f21..840f25b6f3303 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 @@ -228,6 +228,54 @@ public static ArangoDbEndpointBuilderFactory.ArangoDbEndpointBuilder arangodb(St public static ArangoDbEndpointBuilderFactory.ArangoDbEndpointBuilder arangodb(String componentName, String path) { return ArangoDbEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * AS2 (camel-as2) + * Transfer data securely and reliably using the AS2 protocol (RFC4130). + * + * Category: file + * Since: 2.22 + * Maven coordinates: org.apache.camel:camel-as2 + * + * Syntax: as2:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 3 enums and the value can be one of: CLIENT, SERVER, RECEIPT + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param path apiName/methodName + * @return the dsl builder + */ + public static AS2EndpointBuilderFactory.AS2EndpointBuilder as2(String path) { + return as2("as2", path); + } + /** + * AS2 (camel-as2) + * Transfer data securely and reliably using the AS2 protocol (RFC4130). + * + * Category: file + * Since: 2.22 + * Maven coordinates: org.apache.camel:camel-as2 + * + * Syntax: as2:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 3 enums and the value can be one of: CLIENT, SERVER, RECEIPT + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path apiName/methodName + * @return the dsl builder + */ + public static AS2EndpointBuilderFactory.AS2EndpointBuilder as2(String componentName, String path) { + return AS2EndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * Asterisk (camel-asterisk) * Interact with Asterisk PBX Server (VoIP). @@ -348,6 +396,66 @@ public static AtomEndpointBuilderFactory.AtomEndpointBuilder atom(String path) { public static AtomEndpointBuilderFactory.AtomEndpointBuilder atom(String componentName, String path) { return AtomEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * Avro RPC (camel-avro-rpc) + * Produce or consume Apache Avro RPC services. + * + * Category: rpc + * Since: 2.10 + * Maven coordinates: org.apache.camel:camel-avro-rpc + * + * Syntax: avro:transport:host:port/messageName + * + * Path parameter: transport (required) + * Transport to use, can be either http or netty + * There are 2 enums and the value can be one of: http, netty + * + * Path parameter: port (required) + * Port number to use + * + * Path parameter: host (required) + * Hostname to use + * + * Path parameter: messageName + * The name of the message to send. + * + * @param path transport:host:port/messageName + * @return the dsl builder + */ + public static AvroEndpointBuilderFactory.AvroEndpointBuilder avro(String path) { + return avro("avro", path); + } + /** + * Avro RPC (camel-avro-rpc) + * Produce or consume Apache Avro RPC services. + * + * Category: rpc + * Since: 2.10 + * Maven coordinates: org.apache.camel:camel-avro-rpc + * + * Syntax: avro:transport:host:port/messageName + * + * Path parameter: transport (required) + * Transport to use, can be either http or netty + * There are 2 enums and the value can be one of: http, netty + * + * Path parameter: port (required) + * Port number to use + * + * Path parameter: host (required) + * Hostname to use + * + * Path parameter: messageName + * The name of the message to send. + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path transport:host:port/messageName + * @return the dsl builder + */ + public static AvroEndpointBuilderFactory.AvroEndpointBuilder avro(String componentName, String path) { + return AvroEndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * AWS Bedrock (camel-aws-bedrock) * Invoke Model of AWS Bedrock service. @@ -2398,6 +2506,58 @@ public static BonitaEndpointBuilderFactory.BonitaEndpointBuilder bonita(String p public static BonitaEndpointBuilderFactory.BonitaEndpointBuilder bonita(String componentName, String path) { return BonitaEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * Box (camel-box) + * Upload, download and manage files, folders, groups, collaborations, etc. + * on box.com. + * + * Category: cloud,file,api + * Since: 2.14 + * Maven coordinates: org.apache.camel:camel-box + * + * Syntax: box:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 10 enums and the value can be one of: COLLABORATIONS, COMMENTS, + * EVENT_LOGS, FILES, FOLDERS, GROUPS, EVENTS, SEARCH, TASKS, USERS + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param path apiName/methodName + * @return the dsl builder + */ + public static BoxEndpointBuilderFactory.BoxEndpointBuilder box(String path) { + return box("box", path); + } + /** + * Box (camel-box) + * Upload, download and manage files, folders, groups, collaborations, etc. + * on box.com. + * + * Category: cloud,file,api + * Since: 2.14 + * Maven coordinates: org.apache.camel:camel-box + * + * Syntax: box:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 10 enums and the value can be one of: COLLABORATIONS, COMMENTS, + * EVENT_LOGS, FILES, FOLDERS, GROUPS, EVENTS, SEARCH, TASKS, USERS + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path apiName/methodName + * @return the dsl builder + */ + public static BoxEndpointBuilderFactory.BoxEndpointBuilder box(String componentName, String path) { + return BoxEndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * Braintree (camel-braintree) * Process payments using Braintree Payments. @@ -3989,6 +4149,58 @@ public static DfdlEndpointBuilderFactory.DfdlEndpointBuilder dfdl(String path) { public static DfdlEndpointBuilderFactory.DfdlEndpointBuilder dfdl(String componentName, String path) { return DfdlEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * DHIS2 (camel-dhis2) + * Leverages the DHIS2 Java SDK to integrate Apache Camel with the DHIS2 Web + * API. + * + * Category: api + * Since: 4.0 + * Maven coordinates: org.apache.camel:camel-dhis2 + * + * Syntax: dhis2:apiName/methodName + * + * Path parameter: apiName (required) + * API operation (e.g., get) + * There are 5 enums and the value can be one of: POST, RESOURCE_TABLES, + * GET, DELETE, PUT + * + * Path parameter: methodName (required) + * Subject of the API operation (e.g., resource) + * + * @param path apiName/methodName + * @return the dsl builder + */ + public static Dhis2EndpointBuilderFactory.Dhis2EndpointBuilder dhis2(String path) { + return dhis2("dhis2", path); + } + /** + * DHIS2 (camel-dhis2) + * Leverages the DHIS2 Java SDK to integrate Apache Camel with the DHIS2 Web + * API. + * + * Category: api + * Since: 4.0 + * Maven coordinates: org.apache.camel:camel-dhis2 + * + * Syntax: dhis2:apiName/methodName + * + * Path parameter: apiName (required) + * API operation (e.g., get) + * There are 5 enums and the value can be one of: POST, RESOURCE_TABLES, + * GET, DELETE, PUT + * + * Path parameter: methodName (required) + * Subject of the API operation (e.g., resource) + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path apiName/methodName + * @return the dsl builder + */ + public static Dhis2EndpointBuilderFactory.Dhis2EndpointBuilder dhis2(String componentName, String path) { + return Dhis2EndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * DigitalOcean (camel-digitalocean) * Manage Droplets and resources within the DigitalOcean cloud. @@ -4668,14 +4880,11 @@ public static ElasticsearchRestClientEndpointBuilderFactory.ElasticsearchRestCli * Comma-separated list of event types to subscribe to. Event types * correspond to CamelEvent.Type enum values (case-insensitive), for * example: RouteStarted, RouteStopped, ExchangeCompleted, ExchangeFailed. - * Wildcard patterns are supported using a suffix, for example: Route - * matches all route events, Exchange matches all exchange events, and - * matches all events. * * @param path events * @return the dsl builder */ - public static CamelEventEndpointBuilderFactory.CamelEventEndpointBuilder event(String path) { + public static EventEndpointBuilderFactory.EventEndpointBuilder event(String path) { return event("event", path); } /** @@ -4693,17 +4902,14 @@ public static CamelEventEndpointBuilderFactory.CamelEventEndpointBuilder event(S * Comma-separated list of event types to subscribe to. Event types * correspond to CamelEvent.Type enum values (case-insensitive), for * example: RouteStarted, RouteStopped, ExchangeCompleted, ExchangeFailed. - * Wildcard patterns are supported using a suffix, for example: Route - * matches all route events, Exchange matches all exchange events, and - * matches all events. * * @param componentName to use a custom component name for the endpoint * instead of the default name * @param path events * @return the dsl builder */ - public static CamelEventEndpointBuilderFactory.CamelEventEndpointBuilder event(String componentName, String path) { - return CamelEventEndpointBuilderFactory.endpointBuilder(componentName, path); + public static EventEndpointBuilderFactory.EventEndpointBuilder event(String componentName, String path) { + return EventEndpointBuilderFactory.endpointBuilder(componentName, path); } /** * Exec (camel-exec) @@ -4747,6 +4953,60 @@ public static ExecEndpointBuilderFactory.ExecEndpointBuilder exec(String path) { public static ExecEndpointBuilderFactory.ExecEndpointBuilder exec(String componentName, String path) { return ExecEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * FHIR (camel-fhir) + * Exchange information in the healthcare domain using the FHIR (Fast + * Healthcare Interoperability Resources) standard. + * + * Category: api + * Since: 2.23 + * Maven coordinates: org.apache.camel:camel-fhir + * + * Syntax: fhir:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 13 enums and the value can be one of: CAPABILITIES, CREATE, + * DELETE, HISTORY, LOAD_PAGE, META, OPERATION, PATCH, READ, SEARCH, + * TRANSACTION, UPDATE, VALIDATE + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param path apiName/methodName + * @return the dsl builder + */ + public static FhirEndpointBuilderFactory.FhirEndpointBuilder fhir(String path) { + return fhir("fhir", path); + } + /** + * FHIR (camel-fhir) + * Exchange information in the healthcare domain using the FHIR (Fast + * Healthcare Interoperability Resources) standard. + * + * Category: api + * Since: 2.23 + * Maven coordinates: org.apache.camel:camel-fhir + * + * Syntax: fhir:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 13 enums and the value can be one of: CAPABILITIES, CREATE, + * DELETE, HISTORY, LOAD_PAGE, META, OPERATION, PATCH, READ, SEARCH, + * TRANSACTION, UPDATE, VALIDATE + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path apiName/methodName + * @return the dsl builder + */ + public static FhirEndpointBuilderFactory.FhirEndpointBuilder fhir(String componentName, String path) { + return FhirEndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * File (camel-file) * Read and write files. @@ -9372,6 +9632,54 @@ public static KeycloakEndpointBuilderFactory.KeycloakEndpointBuilder keycloak(St public static KeycloakEndpointBuilderFactory.KeycloakEndpointBuilder keycloak(String componentName, String path) { return KeycloakEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * Knative (camel-knative) + * Send and receive events from Knative. + * + * Category: cloud + * Since: 3.15 + * Maven coordinates: org.apache.camel:camel-knative + * + * Syntax: knative:type/typeId + * + * Path parameter: type + * The Knative resource type + * There are 3 enums and the value can be one of: endpoint, channel, event + * + * Path parameter: typeId + * The identifier of the Knative resource + * + * @param path type/typeId + * @return the dsl builder + */ + public static KnativeEndpointBuilderFactory.KnativeEndpointBuilder knative(String path) { + return knative("knative", path); + } + /** + * Knative (camel-knative) + * Send and receive events from Knative. + * + * Category: cloud + * Since: 3.15 + * Maven coordinates: org.apache.camel:camel-knative + * + * Syntax: knative:type/typeId + * + * Path parameter: type + * The Knative resource type + * There are 3 enums and the value can be one of: endpoint, channel, event + * + * Path parameter: typeId + * The identifier of the Knative resource + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path type/typeId + * @return the dsl builder + */ + public static KnativeEndpointBuilderFactory.KnativeEndpointBuilder knative(String componentName, String path) { + return KnativeEndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * KServe (camel-kserve) * Provide access to AI model servers with the KServe standard to run @@ -12040,6 +12348,106 @@ public static OAIPMHEndpointBuilderFactory.OAIPMHEndpointBuilder oaipmh(String p public static OAIPMHEndpointBuilderFactory.OAIPMHEndpointBuilder oaipmh(String componentName, String path) { return OAIPMHEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * Olingo2 (camel-olingo2) + * Communicate with OData 2.0 services using Apache Olingo. + * + * Category: cloud + * Since: 2.14 + * Maven coordinates: org.apache.camel:camel-olingo2 + * + * Syntax: olingo2:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 1 enums and the value can be one of: DEFAULT + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param path apiName/methodName + * @return the dsl builder + */ + @Deprecated + public static Olingo2EndpointBuilderFactory.Olingo2EndpointBuilder olingo2(String path) { + return olingo2("olingo2", path); + } + /** + * Olingo2 (camel-olingo2) + * Communicate with OData 2.0 services using Apache Olingo. + * + * Category: cloud + * Since: 2.14 + * Maven coordinates: org.apache.camel:camel-olingo2 + * + * Syntax: olingo2:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 1 enums and the value can be one of: DEFAULT + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path apiName/methodName + * @return the dsl builder + */ + @Deprecated + public static Olingo2EndpointBuilderFactory.Olingo2EndpointBuilder olingo2(String componentName, String path) { + return Olingo2EndpointBuilderFactory.endpointBuilder(componentName, path); + } + /** + * Olingo4 (camel-olingo4) + * Communicate with OData 4.0 services using Apache Olingo OData API. + * + * Category: cloud + * Since: 2.19 + * Maven coordinates: org.apache.camel:camel-olingo4 + * + * Syntax: olingo4:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 1 enums and the value can be one of: DEFAULT + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param path apiName/methodName + * @return the dsl builder + */ + @Deprecated + public static Olingo4EndpointBuilderFactory.Olingo4EndpointBuilder olingo4(String path) { + return olingo4("olingo4", path); + } + /** + * Olingo4 (camel-olingo4) + * Communicate with OData 4.0 services using Apache Olingo OData API. + * + * Category: cloud + * Since: 2.19 + * Maven coordinates: org.apache.camel:camel-olingo4 + * + * Syntax: olingo4:apiName/methodName + * + * Path parameter: apiName (required) + * What kind of operation to perform + * There are 1 enums and the value can be one of: DEFAULT + * + * Path parameter: methodName (required) + * What sub operation to use for the selected operation + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path apiName/methodName + * @return the dsl builder + */ + @Deprecated + public static Olingo4EndpointBuilderFactory.Olingo4EndpointBuilder olingo4(String componentName, String path) { + return Olingo4EndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * Once (camel-once) * Trigger a single message only once at startup (useful for development and @@ -12911,16 +13319,16 @@ public static PgEventEndpointBuilderFactory.PgEventEndpointBuilder pgevent(Strin /** * PGVector (camel-pgvector) * Perform operations on the PostgreSQL pgvector Vector Database. - * + * * Category: database,ai * Since: 4.19 * Maven coordinates: org.apache.camel:camel-pgvector - * + * * Syntax: pgvector:collection - * + * * Path parameter: collection (required) * The collection (table) name - * + * * @param path collection * @return the dsl builder */ @@ -12930,16 +13338,16 @@ public static PgVectorEndpointBuilderFactory.PgVectorEndpointBuilder pgvector(St /** * PGVector (camel-pgvector) * Perform operations on the PostgreSQL pgvector Vector Database. - * + * * Category: database,ai * Since: 4.19 * Maven coordinates: org.apache.camel:camel-pgvector - * + * * Syntax: pgvector:collection - * + * * Path parameter: collection (required) * The collection (table) name - * + * * @param componentName to use a custom component name for the endpoint * instead of the default name * @param path collection @@ -13840,6 +14248,88 @@ public static SagaEndpointBuilderFactory.SagaEndpointBuilder saga(String path) { public static SagaEndpointBuilderFactory.SagaEndpointBuilder saga(String componentName, String path) { return SagaEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * Salesforce (camel-salesforce) + * Communicate with Salesforce using Java DTOs. + * + * Category: cloud,saas + * Since: 2.12 + * Maven coordinates: org.apache.camel:camel-salesforce + * + * Syntax: salesforce:operationName:topicName + * + * Path parameter: operationName (required) + * The operation to use + * There are 69 enums and the value can be one of: getVersions, + * getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, + * createSObject, updateSObject, deleteSObject, getSObjectWithId, + * upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, + * queryAll, search, apexCall, recent, getEventSchema, createJob, getJob, + * closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, + * getResults, createBatchQuery, getQueryResultIds, getQueryResult, + * getRecentReports, getReportDescription, executeSyncReport, + * executeAsyncReport, getReportInstances, getReportResults, limits, + * approval, approvals, composite-tree, composite-batch, composite, + * compositeRetrieveSObjectCollections, compositeCreateSObjectCollections, + * compositeUpdateSObjectCollections, compositeUpsertSObjectCollections, + * compositeDeleteSObjectCollections, bulk2GetAllJobs, bulk2CreateJob, + * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob, + * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults, + * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob, + * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob, + * bulk2DeleteQueryJob, raw, subscribe, pubSubSubscribe, pubSubPublish + * + * Path parameter: topicName + * The name of the topic/channel to use + * + * @param path operationName:topicName + * @return the dsl builder + */ + public static SalesforceEndpointBuilderFactory.SalesforceEndpointBuilder salesforce(String path) { + return salesforce("salesforce", path); + } + /** + * Salesforce (camel-salesforce) + * Communicate with Salesforce using Java DTOs. + * + * Category: cloud,saas + * Since: 2.12 + * Maven coordinates: org.apache.camel:camel-salesforce + * + * Syntax: salesforce:operationName:topicName + * + * Path parameter: operationName (required) + * The operation to use + * There are 69 enums and the value can be one of: getVersions, + * getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, + * createSObject, updateSObject, deleteSObject, getSObjectWithId, + * upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, + * queryAll, search, apexCall, recent, getEventSchema, createJob, getJob, + * closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, + * getResults, createBatchQuery, getQueryResultIds, getQueryResult, + * getRecentReports, getReportDescription, executeSyncReport, + * executeAsyncReport, getReportInstances, getReportResults, limits, + * approval, approvals, composite-tree, composite-batch, composite, + * compositeRetrieveSObjectCollections, compositeCreateSObjectCollections, + * compositeUpdateSObjectCollections, compositeUpsertSObjectCollections, + * compositeDeleteSObjectCollections, bulk2GetAllJobs, bulk2CreateJob, + * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob, + * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults, + * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob, + * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob, + * bulk2DeleteQueryJob, raw, subscribe, pubSubSubscribe, pubSubPublish + * + * Path parameter: topicName + * The name of the topic/channel to use + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path operationName:topicName + * @return the dsl builder + */ + public static SalesforceEndpointBuilderFactory.SalesforceEndpointBuilder salesforce(String componentName, String path) { + return SalesforceEndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * SAP NetWeaver (camel-sap-netweaver) * Send requests to SAP NetWeaver Gateway using HTTP. @@ -14062,6 +14552,46 @@ public static SedaEndpointBuilderFactory.SedaEndpointBuilder seda(String path) { public static SedaEndpointBuilderFactory.SedaEndpointBuilder seda(String componentName, String path) { return SedaEndpointBuilderFactory.endpointBuilder(componentName, path); } + /** + * ServiceNow (camel-servicenow) + * Interact with ServiceNow via its REST API. + * + * Category: api,cloud,management + * Since: 2.18 + * Maven coordinates: org.apache.camel:camel-servicenow + * + * Syntax: servicenow:instanceName + * + * Path parameter: instanceName (required) + * The ServiceNow instance name + * + * @param path instanceName + * @return the dsl builder + */ + public static ServiceNowEndpointBuilderFactory.ServiceNowEndpointBuilder servicenow(String path) { + return servicenow("servicenow", path); + } + /** + * ServiceNow (camel-servicenow) + * Interact with ServiceNow via its REST API. + * + * Category: api,cloud,management + * Since: 2.18 + * Maven coordinates: org.apache.camel:camel-servicenow + * + * Syntax: servicenow:instanceName + * + * Path parameter: instanceName (required) + * The ServiceNow instance name + * + * @param componentName to use a custom component name for the endpoint + * instead of the default name + * @param path instanceName + * @return the dsl builder + */ + public static ServiceNowEndpointBuilderFactory.ServiceNowEndpointBuilder servicenow(String componentName, String path) { + return ServiceNowEndpointBuilderFactory.endpointBuilder(componentName, path); + } /** * Servlet (camel-servlet) * Serve HTTP requests by a Servlet. From 2faec4b15d6fe1c311e39b6bbcd0f8fff033039d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Mar 2026 00:13:41 +0100 Subject: [PATCH 06/20] CAMEL-21540: Fix generated files to match CI expectations - Remove pgvector from alphabetical nav listing (grouped under AI only) - Fix trailing spaces in javadoc blank comment lines - Update EventEndpointBuilderFactory to CamelEventEndpointBuilderFactory - Update rest-openapi description Co-Authored-By: Claude Opus 4.6 --- docs/components/modules/ROOT/nav.adoc | 1 - .../component/ComponentsBuilderFactory.java | 6 ++-- .../endpoint/StaticEndpointBuilders.java | 34 +++++++++++-------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc index e525948fb1d49..887761cd772f6 100644 --- a/docs/components/modules/ROOT/nav.adoc +++ b/docs/components/modules/ROOT/nav.adoc @@ -313,7 +313,6 @@ ** xref:paho-component.adoc[Paho] ** xref:paho-mqtt5-component.adoc[Paho MQTT 5] ** xref:pdf-component.adoc[PDF] -** xref:pgvector-component.adoc[PGVector] ** xref:platform-http-component.adoc[Platform HTTP] ** xref:plc4x-component.adoc[PLC4X] ** xref:pgevent-component.adoc[PostgresSQL Event] 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 e57b1c8455a7c..918c6b6862212 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 @@ -3997,11 +3997,11 @@ static PgeventComponentBuilderFactory.PgeventComponentBuilder pgevent() { /** * PGVector (camel-pgvector) * Perform operations on the PostgreSQL pgvector Vector Database. - * + * * Category: database,ai * Since: 4.19 * Maven coordinates: org.apache.camel:camel-pgvector - * + * * @return the dsl builder */ static PgvectorComponentBuilderFactory.PgvectorComponentBuilder pgvector() { @@ -4210,7 +4210,7 @@ static RestApiComponentBuilderFactory.RestApiComponentBuilder restApi() { } /** * REST OpenApi (camel-rest-openapi) - * To call REST services using OpenAPI specification as contract. + * To call and expose REST services using OpenAPI specification as contract. * * Category: rest,api * Since: 3.1 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 840f25b6f3303..9b1ae2971c8d1 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 @@ -4880,11 +4880,14 @@ public static ElasticsearchRestClientEndpointBuilderFactory.ElasticsearchRestCli * Comma-separated list of event types to subscribe to. Event types * correspond to CamelEvent.Type enum values (case-insensitive), for * example: RouteStarted, RouteStopped, ExchangeCompleted, ExchangeFailed. + * Wildcard patterns are supported using a suffix, for example: Route + * matches all route events, Exchange matches all exchange events, and + * matches all events. * * @param path events * @return the dsl builder */ - public static EventEndpointBuilderFactory.EventEndpointBuilder event(String path) { + public static CamelEventEndpointBuilderFactory.CamelEventEndpointBuilder event(String path) { return event("event", path); } /** @@ -4902,14 +4905,17 @@ public static EventEndpointBuilderFactory.EventEndpointBuilder event(String path * Comma-separated list of event types to subscribe to. Event types * correspond to CamelEvent.Type enum values (case-insensitive), for * example: RouteStarted, RouteStopped, ExchangeCompleted, ExchangeFailed. + * Wildcard patterns are supported using a suffix, for example: Route + * matches all route events, Exchange matches all exchange events, and + * matches all events. * * @param componentName to use a custom component name for the endpoint * instead of the default name * @param path events * @return the dsl builder */ - public static EventEndpointBuilderFactory.EventEndpointBuilder event(String componentName, String path) { - return EventEndpointBuilderFactory.endpointBuilder(componentName, path); + public static CamelEventEndpointBuilderFactory.CamelEventEndpointBuilder event(String componentName, String path) { + return CamelEventEndpointBuilderFactory.endpointBuilder(componentName, path); } /** * Exec (camel-exec) @@ -13319,16 +13325,16 @@ public static PgEventEndpointBuilderFactory.PgEventEndpointBuilder pgevent(Strin /** * PGVector (camel-pgvector) * Perform operations on the PostgreSQL pgvector Vector Database. - * + * * Category: database,ai * Since: 4.19 * Maven coordinates: org.apache.camel:camel-pgvector - * + * * Syntax: pgvector:collection - * + * * Path parameter: collection (required) * The collection (table) name - * + * * @param path collection * @return the dsl builder */ @@ -13338,16 +13344,16 @@ public static PgVectorEndpointBuilderFactory.PgVectorEndpointBuilder pgvector(St /** * PGVector (camel-pgvector) * Perform operations on the PostgreSQL pgvector Vector Database. - * + * * Category: database,ai * Since: 4.19 * Maven coordinates: org.apache.camel:camel-pgvector - * + * * Syntax: pgvector:collection - * + * * Path parameter: collection (required) * The collection (table) name - * + * * @param componentName to use a custom component name for the endpoint * instead of the default name * @param path collection @@ -14000,7 +14006,7 @@ public static RestApiEndpointBuilderFactory.RestApiEndpointBuilder restApi(Strin } /** * REST OpenApi (camel-rest-openapi) - * To call REST services using OpenAPI specification as contract. + * To call and expose REST services using OpenAPI specification as contract. * * Category: rest,api * Since: 3.1 @@ -14037,7 +14043,7 @@ public static RestOpenApiEndpointBuilderFactory.RestOpenApiEndpointBuilder restO } /** * REST OpenApi (camel-rest-openapi) - * To call REST services using OpenAPI specification as contract. + * To call and expose REST services using OpenAPI specification as contract. * * Category: rest,api * Since: 3.1 @@ -15527,7 +15533,7 @@ public static EventEndpointBuilderFactory.EventEndpointBuilder springEvent(Strin * @return the dsl builder */ public static EventEndpointBuilderFactory.EventEndpointBuilder springEvent(String componentName, String path) { - return EventEndpointBuilderFactory.endpointBuilder(componentName, path); + return CamelEventEndpointBuilderFactory.endpointBuilder(componentName, path); } /** * Spring JDBC (camel-spring-jdbc) From 0f8ee2a8555fcf3e006a9e6b4ff0e5cd1d2b6035 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Mar 2026 00:35:23 +0100 Subject: [PATCH 07/20] CAMEL-21540: Fix springEvent to use EventEndpointBuilderFactory Co-Authored-By: Claude Opus 4.6 --- .../apache/camel/builder/endpoint/StaticEndpointBuilders.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9b1ae2971c8d1..71c450e30d21b 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 @@ -15533,7 +15533,7 @@ public static EventEndpointBuilderFactory.EventEndpointBuilder springEvent(Strin * @return the dsl builder */ public static EventEndpointBuilderFactory.EventEndpointBuilder springEvent(String componentName, String path) { - return CamelEventEndpointBuilderFactory.endpointBuilder(componentName, path); + return EventEndpointBuilderFactory.endpointBuilder(componentName, path); } /** * Spring JDBC (camel-spring-jdbc) From bb64e106af25ce551a5f799d5ed58c70520b0193 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Mar 2026 19:14:56 +0100 Subject: [PATCH 08/20] CAMEL-21540: Add HNSW index creation and similarity search filtering - Add CREATE_INDEX action to create HNSW indexes for faster approximate nearest neighbor search, using the configured distance type - Add CamelPgVectorFilter header to apply SQL WHERE clause filtering on similarity search results (e.g., filter by metadata or text content) - Add integration tests for both features Co-Authored-By: Claude Opus 4.6 --- .../camel/component/pgvector/pgvector.json | 5 +- .../src/main/docs/pgvector-component.adoc | 3 +- .../component/pgvector/PgVectorAction.java | 1 + .../component/pgvector/PgVectorHeaders.java | 7 ++- .../component/pgvector/PgVectorProducer.java | 43 +++++++++++++++-- .../pgvector/PgVectorComponentIT.java | 48 ++++++++++++++++--- 6 files changed, 93 insertions(+), 14 deletions(-) diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json index 69d46599f91e7..5da397f848b78 100644 --- a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json @@ -32,11 +32,12 @@ "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } }, "headers": { - "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, + "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "CREATE_INDEX", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, "CamelPgVectorRecordId": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id of the vector record.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#RECORD_ID" }, "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, - "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" } + "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" }, + "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Example: text_content LIKE '%hello%' or metadata LIKE '%category\\:\\science%'.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" } }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, diff --git a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc index 7470e9dd47f2f..818780b619165 100644 --- a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc +++ b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc @@ -36,10 +36,11 @@ configuration, or autowired from the registry. The following actions are supported via the `CamelPgVectorAction` header: - `CREATE_TABLE` - Creates the pgvector extension and a table with columns: id, text_content, metadata, embedding +- `CREATE_INDEX` - Creates an HNSW index on the embedding column for faster approximate nearest neighbor search. The index uses the distance type configured on the endpoint (cosine, euclidean, or innerProduct) - `DROP_TABLE` - Drops the table - `UPSERT` - Inserts or updates a vector record. The body must be a `List`. Set `CamelPgVectorRecordId` for the ID (auto-generated UUID if not set), `CamelPgVectorTextContent` for text, and `CamelPgVectorMetadata` for metadata - `DELETE` - Deletes a record by `CamelPgVectorRecordId` -- `SIMILARITY_SEARCH` - Searches for similar vectors. The body must be a `List` query vector. Set `CamelPgVectorQueryTopK` for max results (default 3). Returns a `List>` with keys: id, text_content, metadata, distance +- `SIMILARITY_SEARCH` - Searches for similar vectors. The body must be a `List` query vector. Set `CamelPgVectorQueryTopK` for max results (default 3). Optionally set `CamelPgVectorFilter` with a SQL WHERE clause to filter results (e.g., `text_content LIKE '%hello%'`). Returns a `List>` with keys: id, text_content, metadata, distance == LangChain4j Integration diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java index 1a647a4bc7a10..bd2703b6d09e3 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorAction.java @@ -18,6 +18,7 @@ public enum PgVectorAction { CREATE_TABLE, + CREATE_INDEX, DROP_TABLE, UPSERT, DELETE, diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java index eb80eec3fc071..760b8799b794f 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java @@ -22,7 +22,7 @@ public class PgVectorHeaders { @Metadata(description = "The action to be performed.", javaType = "String", - enums = "CREATE_TABLE,DROP_TABLE,UPSERT,DELETE,SIMILARITY_SEARCH") + enums = "CREATE_TABLE,CREATE_INDEX,DROP_TABLE,UPSERT,DELETE,SIMILARITY_SEARCH") public static final String ACTION = "CamelPgVectorAction"; @Metadata(description = "The id of the vector record.", @@ -41,4 +41,9 @@ public class PgVectorHeaders { javaType = "String") public static final String METADATA = "CamelPgVectorMetadata"; + @Metadata(description = "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns." + + " Example: \"text_content LIKE '%hello%'\" or \"metadata LIKE '%category\\\":\\\"science%'\".", + javaType = "String") + public static final String FILTER = "CamelPgVectorFilter"; + } diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java index 02447160f59c2..1ac574a0175e4 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java @@ -59,6 +59,9 @@ public void process(Exchange exchange) { case CREATE_TABLE: createTable(exchange); break; + case CREATE_INDEX: + createIndex(exchange); + break; case DROP_TABLE: dropTable(exchange); break; @@ -109,6 +112,30 @@ private void createTable(Exchange exchange) throws SQLException { } } + private void createIndex(Exchange exchange) throws SQLException { + String tableName = getEndpoint().getCollection(); + String distanceType = getEndpoint().getConfiguration().getDistanceType(); + + String opsClass = switch (distanceType) { + case "euclidean" -> "vector_l2_ops"; + case "innerProduct" -> "vector_ip_ops"; + case "cosine" -> "vector_cosine_ops"; + default -> throw new IllegalArgumentException("Unknown distance type: " + distanceType); + }; + + String sql = String.format( + "CREATE INDEX IF NOT EXISTS %s_embedding_idx ON %s USING hnsw (embedding %s)", + sanitizeIdentifier(tableName), sanitizeIdentifier(tableName), opsClass); + + try (Connection conn = getEndpoint().getDataSource().getConnection()) { + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate(sql); + } + + exchange.getMessage().setBody(true); + } + } + private void dropTable(Exchange exchange) throws SQLException { String tableName = getEndpoint().getCollection(); @@ -173,18 +200,26 @@ private void similaritySearch(Exchange exchange) throws Exception { String tableName = getEndpoint().getCollection(); int topK = in.getHeader(PgVectorHeaders.QUERY_TOP_K, 3, Integer.class); String distanceType = getEndpoint().getConfiguration().getDistanceType(); + String filter = in.getHeader(PgVectorHeaders.FILTER, String.class); List queryVector = in.getMandatoryBody(List.class); float[] vectorArray = toFloatArray(queryVector); String distanceOp = getDistanceOperator(distanceType); - String sql = String.format( - "SELECT id, text_content, metadata, embedding %s ? AS distance FROM %s ORDER BY embedding %s ? LIMIT ?", - distanceOp, sanitizeIdentifier(tableName), distanceOp); + StringBuilder sqlBuilder = new StringBuilder(); + sqlBuilder.append(String.format( + "SELECT id, text_content, metadata, embedding %s ? AS distance FROM %s", + distanceOp, sanitizeIdentifier(tableName))); + + if (filter != null && !filter.isBlank()) { + sqlBuilder.append(" WHERE ").append(filter); + } + + sqlBuilder.append(String.format(" ORDER BY embedding %s ? LIMIT ?", distanceOp)); try (Connection conn = getEndpoint().getDataSource().getConnection()) { PGvector.addVectorType(conn); - try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + try (PreparedStatement pstmt = conn.prepareStatement(sqlBuilder.toString())) { PGvector pgVector = new PGvector(vectorArray); pstmt.setObject(1, pgVector); pstmt.setObject(2, pgVector); diff --git a/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java index a157875e5fe34..91225a57177ac 100644 --- a/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java +++ b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java @@ -77,6 +77,18 @@ public void createTable() { @Test @Order(2) + public void createIndex() { + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.CREATE_INDEX) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(Boolean.class)).isTrue(); + } + + @Test + @Order(3) public void upsert() { List vector = Arrays.asList(0.1f, 0.2f, 0.3f); @@ -84,7 +96,7 @@ public void upsert() { .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) .withHeader(PgVectorHeaders.RECORD_ID, "test-1") .withHeader(PgVectorHeaders.TEXT_CONTENT, "Hello World") - .withHeader(PgVectorHeaders.METADATA, "source=test") + .withHeader(PgVectorHeaders.METADATA, "{\"category\":\"greeting\"}") .withBody(vector) .request(Exchange.class); @@ -94,7 +106,7 @@ public void upsert() { } @Test - @Order(3) + @Order(4) public void upsertSecond() { List vector = Arrays.asList(0.4f, 0.5f, 0.6f); @@ -102,6 +114,7 @@ public void upsertSecond() { .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) .withHeader(PgVectorHeaders.RECORD_ID, "test-2") .withHeader(PgVectorHeaders.TEXT_CONTENT, "Goodbye World") + .withHeader(PgVectorHeaders.METADATA, "{\"category\":\"farewell\"}") .withBody(vector) .request(Exchange.class); @@ -111,7 +124,7 @@ public void upsertSecond() { } @Test - @Order(4) + @Order(5) @SuppressWarnings("unchecked") public void similaritySearch() { List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); @@ -135,7 +148,30 @@ public void similaritySearch() { } @Test - @Order(5) + @Order(6) + @SuppressWarnings("unchecked") + public void similaritySearchWithFilter() { + List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); + + // Filter to only match the "farewell" category — should return test-2 even though test-1 is closer + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.SIMILARITY_SEARCH) + .withHeader(PgVectorHeaders.QUERY_TOP_K, 2) + .withHeader(PgVectorHeaders.FILTER, "metadata LIKE '%farewell%'") + .withBody(queryVector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + + List> results = result.getMessage().getBody(List.class); + assertThat(results).hasSize(1); + assertThat(results.get(0).get("id")).isEqualTo("test-2"); + assertThat(results.get(0).get("text_content")).isEqualTo("Goodbye World"); + } + + @Test + @Order(7) public void delete() { Exchange result = fluentTemplate.to(PGVECTOR_URI) .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DELETE) @@ -148,7 +184,7 @@ public void delete() { } @Test - @Order(6) + @Order(8) @SuppressWarnings("unchecked") public void searchAfterDelete() { List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); @@ -168,7 +204,7 @@ public void searchAfterDelete() { } @Test - @Order(7) + @Order(9) public void dropTable() { Exchange result = fluentTemplate.to(PGVECTOR_URI) .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DROP_TABLE) From 3d78b1d02868128b057dde2e0c1f73bbaeca2654 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Mar 2026 20:02:02 +0100 Subject: [PATCH 09/20] CAMEL-21540: Update generated files for new filter header and create index action Co-Authored-By: Claude Opus 4.6 --- .../apache/camel/catalog/components/pgvector.json | 5 +++-- .../apache/camel/component/pgvector/pgvector.json | 2 +- .../camel/component/pgvector/PgVectorHeaders.java | 5 +++-- .../dsl/PgVectorEndpointBuilderFactory.java | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json index 69d46599f91e7..83265460001c1 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json @@ -32,11 +32,12 @@ "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } }, "headers": { - "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, + "CamelPgVectorAction": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "enum": [ "CREATE_TABLE", "CREATE_INDEX", "DROP_TABLE", "UPSERT", "DELETE", "SIMILARITY_SEARCH" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The action to be performed.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#ACTION" }, "CamelPgVectorRecordId": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id of the vector record.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#RECORD_ID" }, "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, - "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" } + "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" }, + "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Example: text_content LIKE '%hello%'.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" } }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json index 5da397f848b78..83265460001c1 100644 --- a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json @@ -37,7 +37,7 @@ "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" }, - "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Example: text_content LIKE '%hello%' or metadata LIKE '%category\\:\\science%'.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" } + "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Example: text_content LIKE '%hello%'.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" } }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java index 760b8799b794f..992c4a513a155 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java @@ -41,8 +41,9 @@ public class PgVectorHeaders { javaType = "String") public static final String METADATA = "CamelPgVectorMetadata"; - @Metadata(description = "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns." - + " Example: \"text_content LIKE '%hello%'\" or \"metadata LIKE '%category\\\":\\\"science%'\".", + @Metadata(description = "Filter condition for similarity search." + + " Applied as a SQL WHERE clause on the text_content and metadata columns." + + " Example: text_content LIKE '%hello%'.", javaType = "String") public static final String FILTER = "CamelPgVectorFilter"; diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java index fc7c51f279385..5d823c04c4917 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java @@ -307,6 +307,20 @@ public String pgVectorTextContent() { public String pgVectorMetadata() { return "CamelPgVectorMetadata"; } + /** + * Filter condition for similarity search. Applied as a SQL WHERE clause + * on the text_content and metadata columns. Example: text_content LIKE + * '%hello%'. + * + * The option is a: {@code String} type. + * + * Group: producer + * + * @return the name of the header {@code PgVectorFilter}. + */ + public String pgVectorFilter() { + return "CamelPgVectorFilter"; + } } static PgVectorEndpointBuilder endpointBuilder(String componentName, String path) { class PgVectorEndpointBuilderImpl extends AbstractEndpointBuilder implements PgVectorEndpointBuilder, AdvancedPgVectorEndpointBuilder { From 3d5e6b44a9148806ff7089f7246a7ba0aedaefd2 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Mar 2026 22:07:04 +0100 Subject: [PATCH 10/20] CAMEL-21540: Fix docs gulp race condition with dsl target directories Replace ** glob with {*,*/*} for dsl source pattern to prevent scandir of target/ directories created during parallel builds. Co-Authored-By: Claude Opus 4.6 --- docs/gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/gulpfile.js b/docs/gulpfile.js index 39d7dc056961a..beb9d17e70dfa 100644 --- a/docs/gulpfile.js +++ b/docs/gulpfile.js @@ -206,7 +206,7 @@ const sources = { '../core/camel-base/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../core/camel-main/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../components/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', - '../dsl/**/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', + '../dsl/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', ], destination: 'components/modules/others/pages', keep: [ From b8ee61a9a97de0847d45823a8014bafa67d68a65 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 24 Mar 2026 22:38:27 +0100 Subject: [PATCH 11/20] CAMEL-21540: Include dsl/src/main/docs in gulpfile source pattern The dsl.adoc lives at dsl/src/main/docs/ (depth 0), which is not matched by {*,*/*}. Add explicit pattern for it. Co-Authored-By: Claude Opus 4.6 --- docs/gulpfile.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/gulpfile.js b/docs/gulpfile.js index beb9d17e70dfa..d18a25c773062 100644 --- a/docs/gulpfile.js +++ b/docs/gulpfile.js @@ -206,6 +206,7 @@ const sources = { '../core/camel-base/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../core/camel-main/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../components/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', + '../dsl/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../dsl/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', ], destination: 'components/modules/others/pages', From b0260b9588335a8299cba7c8f519dcd14c89fc3c Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 25 Mar 2026 16:08:03 +0100 Subject: [PATCH 12/20] CAMEL-21540: Update openai docs to use pgvector component Replace the raw SQL example with the pgvector component for PostgreSQL vector database integration. Add a similarity search example showing the full index + search workflow. Co-Authored-By: Claude Opus 4.6 --- .../src/main/docs/openai-component.adoc | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc index 4e09e1d24eccb..f2807408c7e3e 100644 --- a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc +++ b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc @@ -420,6 +420,8 @@ For single-input requests, the component returns a raw `List` embedding v ==== PostgreSQL + pgvector (Recommended) +Using the xref:pgvector-component.adoc[PGVector] component: + [source,yaml] ---- # Index documents in PostgreSQL with pgvector @@ -434,16 +436,39 @@ For single-input requests, the component returns a raw `List` embedding v uri: openai:embeddings parameters: embeddingModel: nomic-embed-text - - setVariable: - name: embedding - simple: "${body.toString()}" + - setHeader: + name: CamelPgVectorAction + constant: UPSERT + - setHeader: + name: CamelPgVectorTextContent + simple: "${variable.text}" + - to: + uri: pgvector:documents + +# Similarity search +- route: + from: + uri: direct:search + steps: + - to: + uri: openai:embeddings + parameters: + embeddingModel: nomic-embed-text + - setHeader: + name: CamelPgVectorAction + constant: SIMILARITY_SEARCH + - setHeader: + name: CamelPgVectorQueryTopK + constant: 5 - to: - uri: sql:INSERT INTO documents (content, embedding) VALUES (:#text, :#embedding::vector) + uri: pgvector:documents ---- +The pgvector component handles table creation, HNSW indexing, upsert with conflict resolution, and similarity search with configurable distance types (cosine, euclidean, inner product). See the xref:pgvector-component.adoc[PGVector component documentation] for details. + ==== Alternative: Dedicated Vector Databases -For specialized vector workloads, you can also use `camel-qdrant`, `camel-weaviate`, `camel-milvus`, or `camel-pinecone`: +For specialized vector workloads, you can also use `camel-pgvector`, `camel-qdrant`, `camel-weaviate`, `camel-milvus`, or `camel-pinecone`: === Similarity Calculation From 5d8f0d7adaa66174b969b9427af7bb97ec9e08ea Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 25 Mar 2026 16:11:31 +0100 Subject: [PATCH 13/20] CAMEL-21540: Mention raw SQL alternative for custom schemas Co-Authored-By: Claude Opus 4.6 --- .../camel-openai/src/main/docs/openai-component.adoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc index f2807408c7e3e..3e5d29b4c13fa 100644 --- a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc +++ b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc @@ -466,6 +466,14 @@ Using the xref:pgvector-component.adoc[PGVector] component: The pgvector component handles table creation, HNSW indexing, upsert with conflict resolution, and similarity search with configurable distance types (cosine, euclidean, inner product). See the xref:pgvector-component.adoc[PGVector component documentation] for details. +For custom table schemas, complex queries (joins, CTEs), or integration with existing PostgreSQL tables, you can use `camel-sql` directly with the pgvector extension: + +[source,yaml] +---- +- to: + uri: sql:INSERT INTO documents (content, embedding) VALUES (:#text, :#embedding::vector) +---- + ==== Alternative: Dedicated Vector Databases For specialized vector workloads, you can also use `camel-pgvector`, `camel-qdrant`, `camel-weaviate`, `camel-milvus`, or `camel-pinecone`: From 4b028ff217425da6f8455fd7daa1cfa71ebeefdc Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 25 Mar 2026 16:33:23 +0100 Subject: [PATCH 14/20] CAMEL-21540: Add cross-documentation for pgvector component - Add pgvector examples to langchain4j-embeddings docs (alongside Qdrant) - Add OpenAI and LangChain4j integration examples to pgvector docs Co-Authored-By: Claude Opus 4.6 --- .../langchain4j-embeddings-component.adoc | 71 ++++++++++ .../src/main/docs/pgvector-component.adoc | 124 +++++++++++++++++- 2 files changed, 194 insertions(+), 1 deletion(-) diff --git a/components/camel-ai/camel-langchain4j-embeddings/src/main/docs/langchain4j-embeddings-component.adoc b/components/camel-ai/camel-langchain4j-embeddings/src/main/docs/langchain4j-embeddings-component.adoc index b9328f28701d4..884940a9dc067 100644 --- a/components/camel-ai/camel-langchain4j-embeddings/src/main/docs/langchain4j-embeddings-component.adoc +++ b/components/camel-ai/camel-langchain4j-embeddings/src/main/docs/langchain4j-embeddings-component.adoc @@ -268,6 +268,77 @@ YAML:: ---- ==== +==== Using with PGVector + +This example shows how to embed text and store it in PostgreSQL with pgvector: + +[tabs] +==== +Java:: ++ +[source,java] +---- +from("direct:store") + .to("langchain4j-embeddings:embed") + .setHeader(PgVectorHeaders.ACTION).constant(PgVectorAction.UPSERT) + .transformDataType(new DataType("pgvector:embeddings")) + .to("pgvector:myCollection"); +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: "direct:store" + steps: + - to: "langchain4j-embeddings:embed" + - setHeader: + name: CamelPgVectorAction + constant: UPSERT + - transform: + dataType: "pgvector:embeddings" + - to: "pgvector:myCollection" +---- +==== + +Similarity search with PGVector and RAG: + +[tabs] +==== +Java:: ++ +[source,java] +---- +from("direct:search") + .to("langchain4j-embeddings:embed") + .transformDataType(new DataType("pgvector:embeddings")) + .setHeader(PgVectorHeaders.ACTION, constant(PgVectorAction.SIMILARITY_SEARCH)) + .to("pgvector:myCollection") + .transformDataType(new DataType("pgvector:rag")); +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: "direct:search" + steps: + - to: "langchain4j-embeddings:embed" + - transform: + dataType: "pgvector:embeddings" + - setHeader: + name: CamelPgVectorAction + constant: SIMILARITY_SEARCH + - to: "pgvector:myCollection" + - transform: + dataType: "pgvector:rag" +---- +==== + ==== Using with LangChain4j Embedding Store Component For a simpler integration, use the `langchain4j-embeddingstore` component which provides a unified interface: diff --git a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc index 818780b619165..949b687908c06 100644 --- a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc +++ b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc @@ -42,13 +42,135 @@ The following actions are supported via the `CamelPgVectorAction` header: - `DELETE` - Deletes a record by `CamelPgVectorRecordId` - `SIMILARITY_SEARCH` - Searches for similar vectors. The body must be a `List` query vector. Set `CamelPgVectorQueryTopK` for max results (default 3). Optionally set `CamelPgVectorFilter` with a SQL WHERE clause to filter results (e.g., `text_content LIKE '%hello%'`). Returns a `List>` with keys: id, text_content, metadata, distance +== OpenAI Integration + +The component works directly with the xref:openai-component.adoc[OpenAI] component for embedding generation. +The OpenAI embeddings endpoint returns a `List`, which is exactly the body format expected by the pgvector UPSERT and SIMILARITY_SEARCH actions. + +[tabs] +==== +Java:: ++ +[source,java] +---- +// Index a document +from("direct:index") + .setVariable("text", body()) + .to("openai:embeddings?embeddingModel=nomic-embed-text") + .setHeader(PgVectorHeaders.ACTION).constant(PgVectorAction.UPSERT) + .setHeader(PgVectorHeaders.TEXT_CONTENT).variable("text") + .to("pgvector:documents"); + +// Similarity search +from("direct:search") + .to("openai:embeddings?embeddingModel=nomic-embed-text") + .setHeader(PgVectorHeaders.ACTION).constant(PgVectorAction.SIMILARITY_SEARCH) + .setHeader(PgVectorHeaders.QUERY_TOP_K).constant(5) + .to("pgvector:documents"); +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:index + steps: + - setVariable: + name: text + simple: "${body}" + - to: + uri: openai:embeddings + parameters: + embeddingModel: nomic-embed-text + - setHeader: + name: CamelPgVectorAction + constant: UPSERT + - setHeader: + name: CamelPgVectorTextContent + simple: "${variable.text}" + - to: pgvector:documents + +- route: + from: + uri: direct:search + steps: + - to: + uri: openai:embeddings + parameters: + embeddingModel: nomic-embed-text + - setHeader: + name: CamelPgVectorAction + constant: SIMILARITY_SEARCH + - setHeader: + name: CamelPgVectorQueryTopK + constant: 5 + - to: pgvector:documents +---- +==== + == LangChain4j Integration -This component provides data type transformers for LangChain4j integration: +This component provides data type transformers for xref:langchain4j-embeddings-component.adoc[LangChain4j Embeddings] integration: - `pgvector:embeddings` - Transforms LangChain4j embedding output into a format suitable for the PGVector UPSERT action - `pgvector:rag` - Transforms similarity search results into a `List` for RAG pipelines +[tabs] +==== +Java:: ++ +[source,java] +---- +// Store embeddings +from("direct:store") + .to("langchain4j-embeddings:embed") + .setHeader(PgVectorHeaders.ACTION).constant(PgVectorAction.UPSERT) + .transformDataType(new DataType("pgvector:embeddings")) + .to("pgvector:myCollection"); + +// Similarity search for RAG +from("direct:search") + .to("langchain4j-embeddings:embed") + .transformDataType(new DataType("pgvector:embeddings")) + .setHeader(PgVectorHeaders.ACTION, constant(PgVectorAction.SIMILARITY_SEARCH)) + .to("pgvector:myCollection") + .transformDataType(new DataType("pgvector:rag")); +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: "direct:store" + steps: + - to: "langchain4j-embeddings:embed" + - setHeader: + name: CamelPgVectorAction + constant: UPSERT + - transform: + dataType: "pgvector:embeddings" + - to: "pgvector:myCollection" + +- route: + from: + uri: "direct:search" + steps: + - to: "langchain4j-embeddings:embed" + - transform: + dataType: "pgvector:embeddings" + - setHeader: + name: CamelPgVectorAction + constant: SIMILARITY_SEARCH + - to: "pgvector:myCollection" + - transform: + dataType: "pgvector:rag" +---- +==== + // component options: START include::partial$component-configure-options.adoc[] From 379ac929e11d0e79bff8f03c008ff5913434b9a0 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 26 Mar 2026 23:40:51 +0100 Subject: [PATCH 15/20] Review fixes: improve test coverage and robustness - Make PgVectorHeaders final with private constructor - Add null check for embedding header in data type transformer - Add upsertUpdate test to verify ON CONFLICT DO UPDATE behavior - Add upsertAutoId test to verify auto-generated UUID - Fix test ordering and assertions after adding new tests Co-Authored-By: Claude Opus 4.6 --- .../component/pgvector/PgVectorHeaders.java | 5 +- ...PgVectorEmbeddingsDataTypeTransformer.java | 5 ++ .../pgvector/PgVectorComponentIT.java | 57 ++++++++++++++++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java index 992c4a513a155..e4d9e68c1143e 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java @@ -18,7 +18,10 @@ import org.apache.camel.spi.Metadata; -public class PgVectorHeaders { +public final class PgVectorHeaders { + + private PgVectorHeaders() { + } @Metadata(description = "The action to be performed.", javaType = "String", diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java index 166d8c64f958d..2d6e46d424307 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java @@ -42,6 +42,11 @@ public class PgVectorEmbeddingsDataTypeTransformer extends Transformer { public void transform(Message message, DataType fromType, DataType toType) { Embedding embedding = message.getHeader(CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_EMBEDDING_VECTOR, Embedding.class); + if (embedding == null) { + throw new IllegalArgumentException( + "Missing embedding vector header '" + CamelLangchain4jAttributes.CAMEL_LANGCHAIN4J_EMBEDDING_VECTOR + + "'. Ensure the langchain4j-embeddings component is called before this transformer."); + } TextSegment text = message.getBody(TextSegment.class); String id = message.getHeader(PgVectorHeaders.RECORD_ID, () -> UUID.randomUUID().toString(), String.class); diff --git a/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java index 91225a57177ac..9eaeea12e28fb 100644 --- a/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java +++ b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java @@ -107,6 +107,24 @@ public void upsert() { @Test @Order(4) + public void upsertUpdate() { + // Update test-1 with new text and vector to verify ON CONFLICT DO UPDATE + List vector = Arrays.asList(0.15f, 0.25f, 0.35f); + + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) + .withHeader(PgVectorHeaders.RECORD_ID, "test-1") + .withHeader(PgVectorHeaders.TEXT_CONTENT, "Hello Updated World") + .withBody(vector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(String.class)).isEqualTo("test-1"); + } + + @Test + @Order(5) public void upsertSecond() { List vector = Arrays.asList(0.4f, 0.5f, 0.6f); @@ -124,7 +142,27 @@ public void upsertSecond() { } @Test - @Order(5) + @Order(6) + public void upsertAutoId() { + // Verify auto-generated UUID when no RECORD_ID is provided + List vector = Arrays.asList(0.7f, 0.8f, 0.9f); + + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.UPSERT) + .withHeader(PgVectorHeaders.TEXT_CONTENT, "Auto ID record") + .withBody(vector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + String autoId = result.getMessage().getBody(String.class); + assertThat(autoId).isNotNull(); + // Verify it's a valid UUID format + assertThat(autoId).matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + } + + @Test + @Order(7) @SuppressWarnings("unchecked") public void similaritySearch() { List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); @@ -142,13 +180,13 @@ public void similaritySearch() { assertThat(results).isNotEmpty(); assertThat(results).hasSizeLessThanOrEqualTo(2); - // The closest vector should be test-1 (exact match) + // The closest vector should be test-1 (updated by upsertUpdate test) assertThat(results.get(0).get("id")).isEqualTo("test-1"); - assertThat(results.get(0).get("text_content")).isEqualTo("Hello World"); + assertThat(results.get(0).get("text_content")).isEqualTo("Hello Updated World"); } @Test - @Order(6) + @Order(8) @SuppressWarnings("unchecked") public void similaritySearchWithFilter() { List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); @@ -171,7 +209,7 @@ public void similaritySearchWithFilter() { } @Test - @Order(7) + @Order(9) public void delete() { Exchange result = fluentTemplate.to(PGVECTOR_URI) .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DELETE) @@ -184,7 +222,7 @@ public void delete() { } @Test - @Order(8) + @Order(10) @SuppressWarnings("unchecked") public void searchAfterDelete() { List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); @@ -199,12 +237,13 @@ public void searchAfterDelete() { assertThat(result.getException()).isNull(); List> results = result.getMessage().getBody(List.class); - assertThat(results).hasSize(1); - assertThat(results.get(0).get("id")).isEqualTo("test-2"); + assertThat(results).hasSize(2); + // test-1 was deleted, so results should be test-2 and auto-ID record + assertThat(results).extracting(r -> r.get("id")).doesNotContain("test-1"); } @Test - @Order(9) + @Order(11) public void dropTable() { Exchange result = fluentTemplate.to(PGVECTOR_URI) .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DROP_TABLE) From dfccad64bfc68d38d5231ab27be646e8e365684d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 26 Mar 2026 23:51:26 +0100 Subject: [PATCH 16/20] Add test logging config and fix redundant doc reference - Add log4j2.properties for test logging (consistent with other vector DB components) - Remove redundant camel-pgvector from openai "Alternative" list since it's already recommended above Co-Authored-By: Claude Opus 4.6 --- .../src/main/docs/openai-component.adoc | 2 +- .../src/test/resources/log4j2.properties | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 components/camel-ai/camel-pgvector/src/test/resources/log4j2.properties diff --git a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc index 3e5d29b4c13fa..484534bd3f432 100644 --- a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc +++ b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc @@ -476,7 +476,7 @@ For custom table schemas, complex queries (joins, CTEs), or integration with exi ==== Alternative: Dedicated Vector Databases -For specialized vector workloads, you can also use `camel-pgvector`, `camel-qdrant`, `camel-weaviate`, `camel-milvus`, or `camel-pinecone`: +For specialized vector workloads, you can also use `camel-qdrant`, `camel-weaviate`, `camel-milvus`, or `camel-pinecone`: === Similarity Calculation diff --git a/components/camel-ai/camel-pgvector/src/test/resources/log4j2.properties b/components/camel-ai/camel-pgvector/src/test/resources/log4j2.properties new file mode 100644 index 0000000000000..f325a55302c34 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/test/resources/log4j2.properties @@ -0,0 +1,30 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +appender.file.type = File +appender.file.name = file +appender.file.fileName = target/camel-pgvector-test.log +appender.file.layout.type = PatternLayout +appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n + +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n + +rootLogger.level = INFO +rootLogger.appenderRef.file.ref = file From 315ca00abefb767b28003c9f57de0639b963663a Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 27 Mar 2026 00:24:01 +0100 Subject: [PATCH 17/20] CAMEL-21540: Fix docs gulp race by excluding target dirs from dsl glob The {*,*/*} pattern causes the glob library to scan into target/ directories at the second level, which can race with concurrent test execution deleting target/surefire. Use !(target) extglob to exclude target directories from the scan. Co-Authored-By: Claude Opus 4.6 --- docs/gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/gulpfile.js b/docs/gulpfile.js index d18a25c773062..9880997246ffa 100644 --- a/docs/gulpfile.js +++ b/docs/gulpfile.js @@ -207,7 +207,7 @@ const sources = { '../core/camel-main/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../components/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../dsl/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', - '../dsl/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', + '../dsl/{*,*/!(target)}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', ], destination: 'components/modules/others/pages', keep: [ From 5eb34a84c0e6afe6b6258b0f59e083e0e2412578 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 28 Mar 2026 11:12:50 +0100 Subject: [PATCH 18/20] Review fixes: parameterized filters, distanceType enum, safety improvements - Add FILTER_PARAMS header for parameterized SQL filter queries - Add SQL injection warning to FILTER header documentation - Replace String distanceType with PgVectorDistanceType enum - Fix JSON serialization to preserve numeric/boolean types in metadata - Add null element check in toFloatArray with descriptive error - Add null body check in ReverseEmbeddingsDataTypeTransformer - Document defaults (dimension=384, distanceType=COSINE) and security - Add tests: parameterized filter, missing action header, delete non-existent Co-Authored-By: Claude Opus 4.6 --- .../camel/catalog/components/pgvector.json | 7 +-- .../pgvector/PgVectorComponentConfigurer.java | 4 +- .../PgVectorConfigurationConfigurer.java | 4 +- .../pgvector/PgVectorEndpointConfigurer.java | 4 +- .../camel/component/pgvector/pgvector.json | 7 +-- .../src/main/docs/pgvector-component.adoc | 29 +++++++++- .../pgvector/PgVectorConfiguration.java | 21 +++----- .../pgvector/PgVectorDistanceType.java | 40 ++++++++++++++ .../component/pgvector/PgVectorHeaders.java | 13 ++++- .../component/pgvector/PgVectorProducer.java | 48 ++++++++--------- ...PgVectorEmbeddingsDataTypeTransformer.java | 13 ++++- ...rReverseEmbeddingsDataTypeTransformer.java | 4 ++ .../pgvector/PgVectorComponentIT.java | 53 ++++++++++++++++++- .../dsl/PgvectorComponentBuilderFactory.java | 9 ++-- .../dsl/PgVectorEndpointBuilderFactory.java | 46 ++++++++++++++-- 15 files changed, 237 insertions(+), 65 deletions(-) create mode 100644 components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorDistanceType.java diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json index 83265460001c1..163451d430669 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pgvector.json @@ -27,7 +27,7 @@ "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.pgvector.PgVectorConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The configuration;" }, "dataSource": { "index": 1, "kind": "property", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, "dimension": { "index": 2, "kind": "property", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, - "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "org.apache.camel.component.pgvector.PgVectorDistanceType", "enum": [ "COSINE", "EUCLIDEAN", "INNER_PRODUCT" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "COSINE", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, "lazyStartProducer": { "index": 4, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } }, @@ -37,13 +37,14 @@ "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" }, - "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Example: text_content LIKE '%hello%'.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" } + "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Supports parameterized queries using placeholders with values provided via the CamelPgVectorFilterParams header. WARNING: When not using parameterized queries, the filter value is appended directly as SQL. Never use untrusted input as the filter value without parameterization, as this could lead to SQL injection.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" }, + "CamelPgVectorFilterParams": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "java.util.List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Parameter values for parameterized filter queries. Use with placeholders in the CamelPgVectorFilter header. Example: filter = 'text_content LIKE AND metadata::jsonb-'category' = ' with filterParams = List.of(%hello%, science).", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER_PARAMS" } }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, "dataSource": { "index": 1, "kind": "parameter", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, "dimension": { "index": 2, "kind": "parameter", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, - "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "org.apache.camel.component.pgvector.PgVectorDistanceType", "enum": [ "COSINE", "EUCLIDEAN", "INNER_PRODUCT" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "COSINE", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, "lazyStartProducer": { "index": 4, "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." } } } diff --git a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java index c9b6b44f76369..49501a70110a5 100644 --- a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java +++ b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorComponentConfigurer.java @@ -37,7 +37,7 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "dataSource": getOrCreateConfiguration(target).setDataSource(property(camelContext, javax.sql.DataSource.class, value)); return true; case "dimension": getOrCreateConfiguration(target).setDimension(property(camelContext, int.class, value)); return true; case "distancetype": - case "distanceType": getOrCreateConfiguration(target).setDistanceType(property(camelContext, java.lang.String.class, value)); return true; + case "distanceType": getOrCreateConfiguration(target).setDistanceType(property(camelContext, org.apache.camel.component.pgvector.PgVectorDistanceType.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; default: return false; @@ -59,7 +59,7 @@ public Class getOptionType(String name, boolean ignoreCase) { case "dataSource": return javax.sql.DataSource.class; case "dimension": return int.class; case "distancetype": - case "distanceType": return java.lang.String.class; + case "distanceType": return org.apache.camel.component.pgvector.PgVectorDistanceType.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; default: return null; diff --git a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java index 8bedda0cef915..48387e1f34519 100644 --- a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java +++ b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorConfigurationConfigurer.java @@ -27,7 +27,7 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "dataSource": target.setDataSource(property(camelContext, javax.sql.DataSource.class, value)); return true; case "dimension": target.setDimension(property(camelContext, int.class, value)); return true; case "distancetype": - case "distanceType": target.setDistanceType(property(camelContext, java.lang.String.class, value)); return true; + case "distanceType": target.setDistanceType(property(camelContext, org.apache.camel.component.pgvector.PgVectorDistanceType.class, value)); return true; default: return false; } } @@ -39,7 +39,7 @@ public Class getOptionType(String name, boolean ignoreCase) { case "dataSource": return javax.sql.DataSource.class; case "dimension": return int.class; case "distancetype": - case "distanceType": return java.lang.String.class; + case "distanceType": return org.apache.camel.component.pgvector.PgVectorDistanceType.class; default: return null; } } diff --git a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java index faa4cd7924937..1e3f50746b82b 100644 --- a/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java +++ b/components/camel-ai/camel-pgvector/src/generated/java/org/apache/camel/component/pgvector/PgVectorEndpointConfigurer.java @@ -27,7 +27,7 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "dataSource": target.getConfiguration().setDataSource(property(camelContext, javax.sql.DataSource.class, value)); return true; case "dimension": target.getConfiguration().setDimension(property(camelContext, int.class, value)); return true; case "distancetype": - case "distanceType": target.getConfiguration().setDistanceType(property(camelContext, java.lang.String.class, value)); return true; + case "distanceType": target.getConfiguration().setDistanceType(property(camelContext, org.apache.camel.component.pgvector.PgVectorDistanceType.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; default: return false; @@ -46,7 +46,7 @@ public Class getOptionType(String name, boolean ignoreCase) { case "dataSource": return javax.sql.DataSource.class; case "dimension": return int.class; case "distancetype": - case "distanceType": return java.lang.String.class; + case "distanceType": return org.apache.camel.component.pgvector.PgVectorDistanceType.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; default: return null; diff --git a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json index 83265460001c1..163451d430669 100644 --- a/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json +++ b/components/camel-ai/camel-pgvector/src/generated/resources/META-INF/org/apache/camel/component/pgvector/pgvector.json @@ -27,7 +27,7 @@ "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.pgvector.PgVectorConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The configuration;" }, "dataSource": { "index": 1, "kind": "property", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, "dimension": { "index": 2, "kind": "property", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, - "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "distanceType": { "index": 3, "kind": "property", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "org.apache.camel.component.pgvector.PgVectorDistanceType", "enum": [ "COSINE", "EUCLIDEAN", "INNER_PRODUCT" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "COSINE", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, "lazyStartProducer": { "index": 4, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, "autowiredEnabled": { "index": 5, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." } }, @@ -37,13 +37,14 @@ "CamelPgVectorQueryTopK": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "3", "description": "The maximum number of results to return for similarity search.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#QUERY_TOP_K" }, "CamelPgVectorTextContent": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The text content to store alongside the vector embedding.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#TEXT_CONTENT" }, "CamelPgVectorMetadata": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The metadata associated with the vector record, stored as JSON.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#METADATA" }, - "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Example: text_content LIKE '%hello%'.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" } + "CamelPgVectorFilter": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Filter condition for similarity search. Applied as a SQL WHERE clause on the text_content and metadata columns. Supports parameterized queries using placeholders with values provided via the CamelPgVectorFilterParams header. WARNING: When not using parameterized queries, the filter value is appended directly as SQL. Never use untrusted input as the filter value without parameterization, as this could lead to SQL injection.", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER" }, + "CamelPgVectorFilterParams": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "java.util.List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Parameter values for parameterized filter queries. Use with placeholders in the CamelPgVectorFilter header. Example: filter = 'text_content LIKE AND metadata::jsonb-'category' = ' with filterParams = List.of(%hello%, science).", "constantName": "org.apache.camel.component.pgvector.PgVectorHeaders#FILTER_PARAMS" } }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection (table) name" }, "dataSource": { "index": 1, "kind": "parameter", "displayName": "Data Source", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The DataSource to use for connecting to the PostgreSQL database with pgvector extension." }, "dimension": { "index": 2, "kind": "parameter", "displayName": "Dimension", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 384, "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The dimension of the vectors to store." }, - "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "cosine", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, + "distanceType": { "index": 3, "kind": "parameter", "displayName": "Distance Type", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "org.apache.camel.component.pgvector.PgVectorDistanceType", "enum": [ "COSINE", "EUCLIDEAN", "INNER_PRODUCT" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "COSINE", "configurationClass": "org.apache.camel.component.pgvector.PgVectorConfiguration", "configurationField": "configuration", "description": "The distance type to use for similarity search." }, "lazyStartProducer": { "index": 4, "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 producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." } } } diff --git a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc index 949b687908c06..6048cd9f37fc5 100644 --- a/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc +++ b/components/camel-ai/camel-pgvector/src/main/docs/pgvector-component.adoc @@ -36,12 +36,39 @@ configuration, or autowired from the registry. The following actions are supported via the `CamelPgVectorAction` header: - `CREATE_TABLE` - Creates the pgvector extension and a table with columns: id, text_content, metadata, embedding -- `CREATE_INDEX` - Creates an HNSW index on the embedding column for faster approximate nearest neighbor search. The index uses the distance type configured on the endpoint (cosine, euclidean, or innerProduct) +- `CREATE_INDEX` - Creates an HNSW index on the embedding column for faster approximate nearest neighbor search. The index uses the distance type configured on the endpoint (default: COSINE) - `DROP_TABLE` - Drops the table - `UPSERT` - Inserts or updates a vector record. The body must be a `List`. Set `CamelPgVectorRecordId` for the ID (auto-generated UUID if not set), `CamelPgVectorTextContent` for text, and `CamelPgVectorMetadata` for metadata - `DELETE` - Deletes a record by `CamelPgVectorRecordId` - `SIMILARITY_SEARCH` - Searches for similar vectors. The body must be a `List` query vector. Set `CamelPgVectorQueryTopK` for max results (default 3). Optionally set `CamelPgVectorFilter` with a SQL WHERE clause to filter results (e.g., `text_content LIKE '%hello%'`). Returns a `List>` with keys: id, text_content, metadata, distance +== Defaults + +- *dimension*: `384` (matches common embedding models like `all-MiniLM-L6-v2`) +- *distanceType*: `COSINE` (other options: `EUCLIDEAN`, `INNER_PRODUCT`) + +== Parameterized Filters + +When using the `SIMILARITY_SEARCH` action, you can filter results using a SQL WHERE clause via the +`CamelPgVectorFilter` header. For safe handling of dynamic values, use parameterized queries with `?` +placeholders and provide values via the `CamelPgVectorFilterParams` header: + +[source,java] +---- +from("direct:search") + .setHeader(PgVectorHeaders.ACTION).constant(PgVectorAction.SIMILARITY_SEARCH) + .setHeader(PgVectorHeaders.FILTER).constant("text_content LIKE ? AND metadata::jsonb->>'category' = ?") + .setHeader(PgVectorHeaders.FILTER_PARAMS).constant(List.of("%hello%", "science")) + .to("pgvector:documents"); +---- + +== Security + +The `CamelPgVectorFilter` header value is appended directly as a SQL WHERE clause. When using +static, developer-controlled filter expressions this is safe. However, *never pass untrusted user +input directly as the filter value* without using parameterized queries (`?` placeholders with +`CamelPgVectorFilterParams`), as this could lead to SQL injection. + == OpenAI Integration The component works directly with the xref:openai-component.adoc[OpenAI] component for embedding generation. diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java index e61e1849f0971..aefac8f64e2e3 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorConfiguration.java @@ -16,8 +16,6 @@ */ package org.apache.camel.component.pgvector; -import java.util.Set; - import javax.sql.DataSource; import org.apache.camel.RuntimeCamelException; @@ -30,8 +28,6 @@ @UriParams public class PgVectorConfiguration implements Cloneable { - private static final Set VALID_DISTANCE_TYPES = Set.of("cosine", "euclidean", "innerProduct"); - @Metadata(autowired = true, description = "The DataSource to use for connecting to the PostgreSQL database with pgvector extension.") @UriParam @@ -43,10 +39,9 @@ public class PgVectorConfiguration implements Cloneable { private int dimension = 384; @Metadata(label = "producer", - description = "The distance type to use for similarity search.", - enums = "cosine,euclidean,innerProduct") - @UriParam(defaultValue = "cosine") - private String distanceType = "cosine"; + description = "The distance type to use for similarity search.") + @UriParam(defaultValue = "COSINE") + private PgVectorDistanceType distanceType = PgVectorDistanceType.COSINE; public DataSource getDataSource() { return dataSource; @@ -70,18 +65,14 @@ public void setDimension(int dimension) { this.dimension = dimension; } - public String getDistanceType() { + public PgVectorDistanceType getDistanceType() { return distanceType; } /** - * The distance type to use for similarity search. Supported values: cosine, euclidean, innerProduct. + * The distance type to use for similarity search. Supported values: COSINE, EUCLIDEAN, INNER_PRODUCT. */ - public void setDistanceType(String distanceType) { - if (!VALID_DISTANCE_TYPES.contains(distanceType)) { - throw new IllegalArgumentException( - "Invalid distanceType: " + distanceType + ". Valid values are: " + VALID_DISTANCE_TYPES); - } + public void setDistanceType(PgVectorDistanceType distanceType) { this.distanceType = distanceType; } diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorDistanceType.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorDistanceType.java new file mode 100644 index 0000000000000..471220b0a5330 --- /dev/null +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorDistanceType.java @@ -0,0 +1,40 @@ +/* + * 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.pgvector; + +public enum PgVectorDistanceType { + + COSINE("<=>", "vector_cosine_ops"), + EUCLIDEAN("<->", "vector_l2_ops"), + INNER_PRODUCT("<#>", "vector_ip_ops"); + + private final String operator; + private final String indexOpsClass; + + PgVectorDistanceType(String operator, String indexOpsClass) { + this.operator = operator; + this.indexOpsClass = indexOpsClass; + } + + public String getOperator() { + return operator; + } + + public String getIndexOpsClass() { + return indexOpsClass; + } +} diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java index e4d9e68c1143e..627020c3f9220 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorHeaders.java @@ -46,8 +46,19 @@ private PgVectorHeaders() { @Metadata(description = "Filter condition for similarity search." + " Applied as a SQL WHERE clause on the text_content and metadata columns." - + " Example: text_content LIKE '%hello%'.", + + " Supports parameterized queries using ? placeholders with values provided" + + " via the CamelPgVectorFilterParams header." + + " WARNING: When not using parameterized queries, the filter value is appended" + + " directly as SQL. Never use untrusted input as the filter value without" + + " parameterization, as this could lead to SQL injection.", javaType = "String") public static final String FILTER = "CamelPgVectorFilter"; + @Metadata(description = "Parameter values for parameterized filter queries." + + " Use with ? placeholders in the CamelPgVectorFilter header." + + " Example: filter = 'text_content LIKE ? AND metadata::jsonb->>'category' = ?'" + + " with filterParams = List.of(\"%hello%\", \"science\").", + javaType = "java.util.List") + public static final String FILTER_PARAMS = "CamelPgVectorFilterParams"; + } diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java index 1ac574a0175e4..e8cbb80933774 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/PgVectorProducer.java @@ -114,18 +114,11 @@ private void createTable(Exchange exchange) throws SQLException { private void createIndex(Exchange exchange) throws SQLException { String tableName = getEndpoint().getCollection(); - String distanceType = getEndpoint().getConfiguration().getDistanceType(); - - String opsClass = switch (distanceType) { - case "euclidean" -> "vector_l2_ops"; - case "innerProduct" -> "vector_ip_ops"; - case "cosine" -> "vector_cosine_ops"; - default -> throw new IllegalArgumentException("Unknown distance type: " + distanceType); - }; + PgVectorDistanceType distanceType = getEndpoint().getConfiguration().getDistanceType(); String sql = String.format( "CREATE INDEX IF NOT EXISTS %s_embedding_idx ON %s USING hnsw (embedding %s)", - sanitizeIdentifier(tableName), sanitizeIdentifier(tableName), opsClass); + sanitizeIdentifier(tableName), sanitizeIdentifier(tableName), distanceType.getIndexOpsClass()); try (Connection conn = getEndpoint().getDataSource().getConnection()) { try (Statement stmt = conn.createStatement()) { @@ -149,6 +142,7 @@ private void dropTable(Exchange exchange) throws SQLException { } } + @SuppressWarnings("unchecked") private void upsert(Exchange exchange) throws Exception { final Message in = exchange.getMessage(); String tableName = getEndpoint().getCollection(); @@ -195,17 +189,19 @@ private void delete(Exchange exchange) throws Exception { } } + @SuppressWarnings("unchecked") private void similaritySearch(Exchange exchange) throws Exception { final Message in = exchange.getMessage(); String tableName = getEndpoint().getCollection(); int topK = in.getHeader(PgVectorHeaders.QUERY_TOP_K, 3, Integer.class); - String distanceType = getEndpoint().getConfiguration().getDistanceType(); + PgVectorDistanceType distanceType = getEndpoint().getConfiguration().getDistanceType(); String filter = in.getHeader(PgVectorHeaders.FILTER, String.class); + List filterParams = in.getHeader(PgVectorHeaders.FILTER_PARAMS, List.class); List queryVector = in.getMandatoryBody(List.class); float[] vectorArray = toFloatArray(queryVector); - String distanceOp = getDistanceOperator(distanceType); + String distanceOp = distanceType.getOperator(); StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append(String.format( "SELECT id, text_content, metadata, embedding %s ? AS distance FROM %s", @@ -220,10 +216,19 @@ private void similaritySearch(Exchange exchange) throws Exception { try (Connection conn = getEndpoint().getDataSource().getConnection()) { PGvector.addVectorType(conn); try (PreparedStatement pstmt = conn.prepareStatement(sqlBuilder.toString())) { + int paramIdx = 1; PGvector pgVector = new PGvector(vectorArray); - pstmt.setObject(1, pgVector); - pstmt.setObject(2, pgVector); - pstmt.setInt(3, topK); + pstmt.setObject(paramIdx++, pgVector); + + // Bind filter parameters if provided + if (filter != null && !filter.isBlank() && filterParams != null) { + for (Object param : filterParams) { + pstmt.setObject(paramIdx++, param); + } + } + + pstmt.setObject(paramIdx++, pgVector); + pstmt.setInt(paramIdx, topK); try (ResultSet rs = pstmt.executeQuery()) { List> results = new ArrayList<>(); @@ -250,20 +255,15 @@ private void similaritySearch(Exchange exchange) throws Exception { private static float[] toFloatArray(List vector) { float[] result = new float[vector.size()]; for (int i = 0; i < vector.size(); i++) { - result[i] = vector.get(i); + Float value = vector.get(i); + if (value == null) { + throw new IllegalArgumentException("Vector contains null value at index " + i); + } + result[i] = value; } return result; } - private static String getDistanceOperator(String distanceType) { - return switch (distanceType) { - case "euclidean" -> "<->"; - case "innerProduct" -> "<#>"; - case "cosine" -> "<=>"; - default -> throw new IllegalArgumentException("Unknown distance type: " + distanceType); - }; - } - private static String sanitizeIdentifier(String identifier) { if (!identifier.matches("[a-zA-Z_][a-zA-Z0-9_]*")) { throw new IllegalArgumentException("Invalid SQL identifier: " + identifier); diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java index 2d6e46d424307..33a815f943d7c 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorEmbeddingsDataTypeTransformer.java @@ -65,12 +65,21 @@ public void transform(Message message, DataType fromType, DataType toType) { private static String toJson(Map map) { return "{" + map.entrySet().stream() - .map(e -> "\"" + escapeJson(String.valueOf(e.getKey())) + "\":\"" - + escapeJson(String.valueOf(e.getValue())) + "\"") + .map(e -> "\"" + escapeJson(String.valueOf(e.getKey())) + "\":" + formatJsonValue(e.getValue())) .collect(Collectors.joining(",")) + "}"; } + private static String formatJsonValue(Object value) { + if (value == null) { + return "null"; + } + if (value instanceof Number || value instanceof Boolean) { + return String.valueOf(value); + } + return "\"" + escapeJson(String.valueOf(value)) + "\""; + } + private static String escapeJson(String value) { return value.replace("\\", "\\\\") .replace("\"", "\\\"") diff --git a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java index 593b8f0f0c8a0..76900cdf1993d 100644 --- a/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java +++ b/components/camel-ai/camel-pgvector/src/main/java/org/apache/camel/component/pgvector/transform/PgVectorReverseEmbeddingsDataTypeTransformer.java @@ -36,6 +36,10 @@ public class PgVectorReverseEmbeddingsDataTypeTransformer extends Transformer { @SuppressWarnings("unchecked") public void transform(Message message, DataType from, DataType to) throws Exception { List> results = message.getBody(List.class); + if (results == null) { + throw new IllegalArgumentException( + "Message body must contain similarity search results (List>)"); + } List textContents = results.stream() .map(row -> (String) row.getOrDefault("text_content", "")) diff --git a/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java index 9eaeea12e28fb..bc1070638eb00 100644 --- a/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java +++ b/components/camel-ai/camel-pgvector/src/test/java/org/apache/camel/component/pgvector/PgVectorComponentIT.java @@ -22,6 +22,7 @@ import org.apache.camel.CamelContext; import org.apache.camel.Exchange; +import org.apache.camel.NoSuchHeaderException; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.test.infra.postgres.services.PostgresService; @@ -210,6 +211,30 @@ public void similaritySearchWithFilter() { @Test @Order(9) + @SuppressWarnings("unchecked") + public void similaritySearchWithParameterizedFilter() { + List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); + + // Same filter as above but using parameterized query for safety + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.SIMILARITY_SEARCH) + .withHeader(PgVectorHeaders.QUERY_TOP_K, 2) + .withHeader(PgVectorHeaders.FILTER, "metadata LIKE ?") + .withHeader(PgVectorHeaders.FILTER_PARAMS, List.of("%farewell%")) + .withBody(queryVector) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + + List> results = result.getMessage().getBody(List.class); + assertThat(results).hasSize(1); + assertThat(results.get(0).get("id")).isEqualTo("test-2"); + assertThat(results.get(0).get("text_content")).isEqualTo("Goodbye World"); + } + + @Test + @Order(10) public void delete() { Exchange result = fluentTemplate.to(PGVECTOR_URI) .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DELETE) @@ -222,7 +247,7 @@ public void delete() { } @Test - @Order(10) + @Order(11) @SuppressWarnings("unchecked") public void searchAfterDelete() { List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f); @@ -243,7 +268,31 @@ public void searchAfterDelete() { } @Test - @Order(11) + @Order(12) + public void missingActionHeader() { + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withBody(Arrays.asList(0.1f, 0.2f, 0.3f)) + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isInstanceOf(NoSuchHeaderException.class); + } + + @Test + @Order(13) + public void deleteNonExistentRecord() { + Exchange result = fluentTemplate.to(PGVECTOR_URI) + .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DELETE) + .withHeader(PgVectorHeaders.RECORD_ID, "non-existent-id") + .request(Exchange.class); + + assertThat(result).isNotNull(); + assertThat(result.getException()).isNull(); + assertThat(result.getMessage().getBody(Boolean.class)).isFalse(); + } + + @Test + @Order(14) public void dropTable() { Exchange result = fluentTemplate.to(PGVECTOR_URI) .withHeader(PgVectorHeaders.ACTION, PgVectorAction.DROP_TABLE) diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java index 564df1a3f7492..0ce0c76d964cf 100644 --- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java +++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PgvectorComponentBuilderFactory.java @@ -103,15 +103,16 @@ default PgvectorComponentBuilder dimension(int dimension) { /** * The distance type to use for similarity search. * - * The option is a: <code>java.lang.String</code> type. + * The option is a: + * <code>org.apache.camel.component.pgvector.PgVectorDistanceType</code> type. * - * Default: cosine + * Default: COSINE * Group: producer * * @param distanceType the value to set * @return the dsl builder */ - default PgvectorComponentBuilder distanceType(java.lang.String distanceType) { + default PgvectorComponentBuilder distanceType(org.apache.camel.component.pgvector.PgVectorDistanceType distanceType) { doSetProperty("distanceType", distanceType); return this; } @@ -186,7 +187,7 @@ protected boolean setPropertyOnComponent( case "configuration": ((PgVectorComponent) component).setConfiguration((org.apache.camel.component.pgvector.PgVectorConfiguration) value); return true; case "dataSource": getOrCreateConfiguration((PgVectorComponent) component).setDataSource((javax.sql.DataSource) value); return true; case "dimension": getOrCreateConfiguration((PgVectorComponent) component).setDimension((int) value); return true; - case "distanceType": getOrCreateConfiguration((PgVectorComponent) component).setDistanceType((java.lang.String) value); return true; + case "distanceType": getOrCreateConfiguration((PgVectorComponent) component).setDistanceType((org.apache.camel.component.pgvector.PgVectorDistanceType) value); return true; case "lazyStartProducer": ((PgVectorComponent) component).setLazyStartProducer((boolean) value); return true; case "autowiredEnabled": ((PgVectorComponent) component).setAutowiredEnabled((boolean) value); return true; default: return false; diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java index 5d823c04c4917..33c8f592f8696 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PgVectorEndpointBuilderFactory.java @@ -108,9 +108,28 @@ default PgVectorEndpointBuilder dimension(String dimension) { /** * The distance type to use for similarity search. * - * The option is a: java.lang.String type. + * The option is a: + * org.apache.camel.component.pgvector.PgVectorDistanceType + * type. * - * Default: cosine + * Default: COSINE + * Group: producer + * + * @param distanceType the value to set + * @return the dsl builder + */ + default PgVectorEndpointBuilder distanceType(org.apache.camel.component.pgvector.PgVectorDistanceType distanceType) { + doSetProperty("distanceType", distanceType); + return this; + } + /** + * The distance type to use for similarity search. + * + * The option will be converted to a + * org.apache.camel.component.pgvector.PgVectorDistanceType + * type. + * + * Default: COSINE * Group: producer * * @param distanceType the value to set @@ -309,8 +328,12 @@ public String pgVectorMetadata() { } /** * Filter condition for similarity search. Applied as a SQL WHERE clause - * on the text_content and metadata columns. Example: text_content LIKE - * '%hello%'. + * on the text_content and metadata columns. Supports parameterized + * queries using placeholders with values provided via the + * CamelPgVectorFilterParams header. WARNING: When not using + * parameterized queries, the filter value is appended directly as SQL. + * Never use untrusted input as the filter value without + * parameterization, as this could lead to SQL injection. * * The option is a: {@code String} type. * @@ -321,6 +344,21 @@ public String pgVectorMetadata() { public String pgVectorFilter() { return "CamelPgVectorFilter"; } + /** + * Parameter values for parameterized filter queries. Use with + * placeholders in the CamelPgVectorFilter header. Example: filter = + * 'text_content LIKE AND metadata::jsonb-'category' = ' with + * filterParams = List.of(%hello%, science). + * + * The option is a: {@code java.util.List} type. + * + * Group: producer + * + * @return the name of the header {@code PgVectorFilterParams}. + */ + public String pgVectorFilterParams() { + return "CamelPgVectorFilterParams"; + } } static PgVectorEndpointBuilder endpointBuilder(String componentName, String path) { class PgVectorEndpointBuilderImpl extends AbstractEndpointBuilder implements PgVectorEndpointBuilder, AdvancedPgVectorEndpointBuilder { From b5d18c841212ff06c43f33a161fe00548a013e23 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 28 Mar 2026 11:44:12 +0100 Subject: [PATCH 19/20] Fix docs gulp race: also ignore target directory entries during glob walk The ignore pattern '**/target/**' only matches paths within target/ but not the target directory entry itself. This allows glob to enter the directory and race with surefire creating/deleting target/surefire. Add '**/target' to also skip the directory entry during walk. Co-Authored-By: Claude Opus 4.6 --- docs/gulpfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/gulpfile.js b/docs/gulpfile.js index 9880997246ffa..23e1a1f286b28 100644 --- a/docs/gulpfile.js +++ b/docs/gulpfile.js @@ -327,7 +327,7 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => { } }) - return gulp.src(source, { ignore: ['**/target/**'] }) + return gulp.src(source, { ignore: ['**/target/**', '**/target'] }) .pipe(filterFn) .pipe( map((file, done) => { @@ -410,7 +410,7 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => { return done() } - return gulp.src(source, { ignore: ['**/target/**'] }) // asciidoc files + return gulp.src(source, { ignore: ['**/target/**', '**/target'] }) // asciidoc files .pipe(through2.obj(extractExamples)) // extracted example files // symlink links from a fixed directory, i.e. we could link to // the example files from `destination`, that would not work for From 43e5b2ed5a9bf74b9dea95d9349453d5960ce4fd Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 28 Mar 2026 12:13:46 +0100 Subject: [PATCH 20/20] Fix docs gulp race: replace !(target) extglob with split patterns The !(target) extglob pattern forces the glob library to enumerate directory contents for negation evaluation, which races with surefire creating/deleting target/surefire during parallel test execution. Replace the single pattern with !(target) negation: ../dsl/{*,*/!(target)}/src/main/docs/... with two simple patterns without negation: ../dsl/*/src/main/docs/... ../dsl/*/*/src/main/docs/... The ignore: ['**/target/**', '**/target'] option on gulp.src() handles filtering out any target directory matches. Co-Authored-By: Claude Opus 4.6 --- docs/gulpfile.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/gulpfile.js b/docs/gulpfile.js index 23e1a1f286b28..4df446b08efca 100644 --- a/docs/gulpfile.js +++ b/docs/gulpfile.js @@ -207,7 +207,8 @@ const sources = { '../core/camel-main/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../components/{*,*/*}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', '../dsl/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', - '../dsl/{*,*/!(target)}/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', + '../dsl/*/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', + '../dsl/*/*/src/main/docs/!(*-component|*-language|*-dataformat|*-summary).adoc', ], destination: 'components/modules/others/pages', keep: [