From 8a1dcfc2250f054b1c068348b1f50f9ff12a8461 Mon Sep 17 00:00:00 2001 From: Soby Chacko Date: Thu, 13 Mar 2025 20:58:33 -0400 Subject: [PATCH] Conditionally enable invidividual vector store implementations - Introduce top level properties to support conditional logic - The properties will have the format like "spring.ai.vectorstore.type=" to enable specific vectore store implementation - By default, these will be enabled when no specific properties are set. To disable, set any value other than the provider name for example, none" Signed-off-by: Soby Chacko --- .../CosmosDBVectorStoreAutoConfiguration.java | 4 ++ ...osmosDBVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../AzureVectorStoreAutoConfiguration.java | 4 +- .../AzureVectorStoreAutoConfigurationIT.java | 27 ++++++++ ...CassandraVectorStoreAutoConfiguration.java | 4 ++ ...ssandraVectorStoreAutoConfigurationIT.java | 38 +++++++++++ .../ChromaVectorStoreAutoConfiguration.java | 4 ++ .../ChromaVectorStoreAutoConfigurationIT.java | 33 ++++++++++ ...ticsearchVectorStoreAutoConfiguration.java | 4 ++ ...csearchVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../GemFireVectorStoreAutoConfiguration.java | 4 +- ...GemFireVectorStoreAutoConfigurationIT.java | 27 ++++++++ ...HanaCloudVectorStoreAutoConfiguration.java | 5 +- .../MariaDbStoreAutoConfiguration.java | 4 ++ .../MariaDbStoreAutoConfigurationIT.java | 28 +++++++++ .../MilvusVectorStoreAutoConfiguration.java | 4 ++ .../MilvusVectorStoreAutoConfigurationIT.java | 35 +++++++++++ ...goDBAtlasVectorStoreAutoConfiguration.java | 4 ++ ...DBAtlasVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../Neo4jVectorStoreAutoConfiguration.java | 4 ++ .../Neo4jVectorStoreAutoConfigurationIT.java | 28 +++++++++ ...penSearchVectorStoreAutoConfiguration.java | 4 ++ ...nSearchVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../OracleVectorStoreAutoConfiguration.java | 4 ++ .../OracleVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../PgVectorStoreAutoConfiguration.java | 4 ++ .../PgVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../PineconeVectorStoreAutoConfiguration.java | 4 ++ ...ineconeVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../QdrantVectorStoreAutoConfiguration.java | 4 ++ .../QdrantVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../RedisVectorStoreAutoConfiguration.java | 4 ++ .../RedisVectorStoreAutoConfigurationIT.java | 28 +++++++++ ...TypesenseVectorStoreAutoConfiguration.java | 4 ++ ...pesenseVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../WeaviateVectorStoreAutoConfiguration.java | 4 ++ ...eaviateVectorStoreAutoConfigurationIT.java | 28 +++++++++ .../vectorstore/SpringAIVectorStoreTypes.java | 63 +++++++++++++++++++ 38 files changed, 661 insertions(+), 3 deletions(-) create mode 100644 spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java index 9f3609ef6..5fdc1686b 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/main/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfiguration.java @@ -23,12 +23,14 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.cosmosdb.CosmosDBVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import java.util.List; @@ -43,6 +45,8 @@ import java.util.List; @AutoConfiguration @ConditionalOnClass({ CosmosDBVectorStore.class, EmbeddingModel.class, CosmosAsyncClient.class }) @EnableConfigurationProperties(CosmosDBVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.AZURE_COSMOS_DB, + matchIfMissing = true) public class CosmosDBVectorStoreAutoConfiguration { String endpoint; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/test/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/test/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfigurationIT.java index 1912e1409..69a0175f2 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/test/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db/src/test/java/org/springframework/ai/vectorstore/cosmosdb/autoconfigure/CosmosDBVectorStoreAutoConfigurationIT.java @@ -31,6 +31,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.ai.vectorstore.cosmosdb.CosmosDBVectorStore; import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -169,6 +170,33 @@ public class CosmosDBVectorStoreAutoConfigurationIT { assertThat(results4).isEmpty(); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(CosmosDBVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(CosmosDBVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(CosmosDBVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(CosmosDBVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsAzureCosmosDB() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=azure-cosmmos-db").run(context -> { + assertThat(context.getBeansOfType(CosmosDBVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(CosmosDBVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/main/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/main/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfiguration.java index efd07c513..9cc64a613 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/main/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/main/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfiguration.java @@ -28,6 +28,7 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.azure.AzureVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; @@ -47,7 +48,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass({ EmbeddingModel.class, SearchIndexClient.class, AzureVectorStore.class }) @EnableConfigurationProperties({ AzureVectorStoreProperties.class }) -@ConditionalOnProperty(prefix = "spring.ai.vectorstore.azure", value = { "url", "api-key", "index-name" }) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.AZURE, + matchIfMissing = true) public class AzureVectorStoreAutoConfiguration { private static final String APPLICATION_ID = "spring-ai"; diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/test/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/test/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfigurationIT.java index 66ba09fa6..21232d279 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/test/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure/src/test/java/org/springframework/ai/vectorstore/azure/autoconfigure/AzureVectorStoreAutoConfigurationIT.java @@ -146,6 +146,33 @@ public class AzureVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(AzureVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(AzureVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(AzureVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(AzureVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsAzure() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=azure").run(context -> { + assertThat(context.getBeansOfType(AzureVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(AzureVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java index 680792639..6bc5f7935 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/main/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfiguration.java @@ -25,6 +25,7 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; @@ -33,6 +34,7 @@ import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfigurati import org.springframework.boot.autoconfigure.cassandra.DriverConfigLoaderBuilderCustomizer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -47,6 +49,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration(after = CassandraAutoConfiguration.class) @ConditionalOnClass({ CassandraVectorStore.class, CqlSession.class }) @EnableConfigurationProperties(CassandraVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.CASSANDRA, + matchIfMissing = true) public class CassandraVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java index b0eeccaa1..34a609571 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-cassandra/src/test/java/org/springframework/ai/vectorstore/cassandra/autoconfigure/CassandraVectorStoreAutoConfigurationIT.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import io.micrometer.observation.tck.TestObservationRegistry; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.testcontainers.containers.CassandraContainer; import org.testcontainers.junit.jupiter.Container; @@ -34,6 +35,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; @@ -111,6 +113,42 @@ class CassandraVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(CassandraVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(CassandraVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.withPropertyValues("spring.cassandra.contactPoints=" + getContactPointHost()) + .withPropertyValues("spring.cassandra.port=" + getContactPointPort()) + .withPropertyValues("spring.cassandra.localDatacenter=" + cassandraContainer.getLocalDatacenter()) + .withPropertyValues("spring.ai.vectorstore.cassandra.fixedThreadPoolExecutorSize=8") + .run(context -> { + assertThat(context.getBeansOfType(CassandraVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(CassandraVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsCassandra() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=cassandra") + .withPropertyValues("spring.cassandra.contactPoints=" + getContactPointHost()) + .withPropertyValues("spring.cassandra.port=" + getContactPointPort()) + .withPropertyValues("spring.cassandra.localDatacenter=" + cassandraContainer.getLocalDatacenter()) + .withPropertyValues("spring.ai.vectorstore.cassandra.fixedThreadPoolExecutorSize=8") + .run(context -> { + assertThat(context.getBeansOfType(CassandraVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(CassandraVectorStore.class); + }); + } + private String getContactPointHost() { return cassandraContainer.getContactPoint().getHostString(); } diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfiguration.java index 4f322229f..2296180b4 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/main/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfiguration.java @@ -24,11 +24,13 @@ import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; import org.springframework.ai.chroma.vectorstore.ChromaVectorStore; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.util.StringUtils; @@ -45,6 +47,8 @@ import org.springframework.web.client.RestClient; @AutoConfiguration @ConditionalOnClass({ EmbeddingModel.class, RestClient.class, ChromaVectorStore.class, ObjectMapper.class }) @EnableConfigurationProperties({ ChromaApiProperties.class, ChromaVectorStoreProperties.class }) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.CHROMA, + matchIfMissing = true) public class ChromaVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/test/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/test/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfigurationIT.java index 56cfb3d29..d84d3e9dc 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/test/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-chroma/src/test/java/org/springframework/ai/vectorstore/chroma/autoconfigure/ChromaVectorStoreAutoConfigurationIT.java @@ -28,6 +28,7 @@ import org.testcontainers.chromadb.ChromaDBContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import org.springframework.ai.chroma.vectorstore.ChromaVectorStore; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.observation.conventions.VectorStoreProvider; @@ -145,6 +146,38 @@ public class ChromaVectorStoreAutoConfigurationIT { "Collection TestCollection doesn't exist and won't be created as the initializeSchema is set to false.")); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(ChromaVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(ChromaVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + @Disabled + public void autoConfigurationEnabledByDefault() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.chroma.initializeSchema=true").run(context -> { + assertThat(context.getBeansOfType(ChromaVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(ChromaVectorStore.class); + }); + } + + @Test + @Disabled + public void autoConfigurationEnabledWhenTypeIsChroma() { + this.contextRunner + .withPropertyValues("spring.ai.vectorstore.type=chroma", + "spring.ai.vectorstore.chroma.initializeSchema=true") + .run(context -> { + assertThat(context.getBeansOfType(ChromaVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(ChromaVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java index 504edc080..5327f46ff 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/main/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfiguration.java @@ -22,6 +22,7 @@ import org.elasticsearch.client.RestClient; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStore; import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStoreOptions; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; @@ -29,6 +30,7 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -47,6 +49,8 @@ import org.springframework.util.StringUtils; @AutoConfiguration(after = ElasticsearchRestClientAutoConfiguration.class) @ConditionalOnClass({ ElasticsearchVectorStore.class, EmbeddingModel.class, RestClient.class }) @EnableConfigurationProperties(ElasticsearchVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.ELASTICSEARCH, + matchIfMissing = true) public class ElasticsearchVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java index 94395dcb8..d2c194ce6 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-elasticsearch/src/test/java/org/springframework/ai/vectorstore/elasticsearch/autoconfigure/ElasticsearchVectorStoreAutoConfigurationIT.java @@ -34,6 +34,7 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration import org.springframework.ai.document.Document; import org.springframework.ai.observation.conventions.VectorStoreProvider; import org.springframework.ai.test.vectorstore.ObservationTestUtil; +import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStore; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.elasticsearch.SimilarityFunction; @@ -149,6 +150,33 @@ class ElasticsearchVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(ElasticsearchVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(ElasticsearchVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(ElasticsearchVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(ElasticsearchVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsElasticsearch() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=elasticsearch").run(context -> { + assertThat(context.getBeansOfType(ElasticsearchVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(ElasticsearchVectorStore.class); + }); + } + private String getText(String uri) { var resource = new DefaultResourceLoader().getResource(uri); try { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/main/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/main/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfiguration.java index d91c59654..18014afbb 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/main/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/main/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfiguration.java @@ -21,6 +21,7 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.gemfire.GemFireVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; @@ -41,7 +42,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass({ GemFireVectorStore.class, EmbeddingModel.class }) @EnableConfigurationProperties(GemFireVectorStoreProperties.class) -@ConditionalOnProperty(prefix = "spring.ai.vectorstore.gemfire", value = { "index-name" }) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.GEMFIRE, + matchIfMissing = true) public class GemFireVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/test/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/test/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfigurationIT.java index 5d1610dcc..40b92b6da 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/test/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-gemfire/src/test/java/org/springframework/ai/vectorstore/gemfire/autoconfigure/GemFireVectorStoreAutoConfigurationIT.java @@ -185,6 +185,33 @@ class GemFireVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(GemFireVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(GemFireVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(GemFireVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(GemFireVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsGemfire() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=gemfire").run(context -> { + assertThat(context.getBeansOfType(GemFireVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(GemFireVectorStore.class); + }); + } + private Map parseIndex(String json) { try { JsonNode rootNode = new ObjectMapper().readTree(json); diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-hanadb/src/main/java/org/springframework/ai/vectorstore/hanadb/autoconfigure/HanaCloudVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-hanadb/src/main/java/org/springframework/ai/vectorstore/hanadb/autoconfigure/HanaCloudVectorStoreAutoConfiguration.java index 557fdfb9b..f2fa1b055 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-hanadb/src/main/java/org/springframework/ai/vectorstore/hanadb/autoconfigure/HanaCloudVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-hanadb/src/main/java/org/springframework/ai/vectorstore/hanadb/autoconfigure/HanaCloudVectorStoreAutoConfiguration.java @@ -21,15 +21,16 @@ import javax.sql.DataSource; import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.EmbeddingModel; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.hanadb.HanaCloudVectorStore; import org.springframework.ai.vectorstore.hanadb.HanaVectorEntity; import org.springframework.ai.vectorstore.hanadb.HanaVectorRepository; -import org.springframework.ai.vectorstore.hanadb.autoconfigure.HanaCloudVectorStoreProperties; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -45,6 +46,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration(after = { JpaRepositoriesAutoConfiguration.class }) @ConditionalOnClass({ HanaCloudVectorStore.class, DataSource.class, HanaVectorEntity.class }) @EnableConfigurationProperties(HanaCloudVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.HANADB, + matchIfMissing = true) public class HanaCloudVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java index 3ac27518c..c8a740398 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/main/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfiguration.java @@ -20,12 +20,14 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -40,6 +42,8 @@ import javax.sql.DataSource; @AutoConfiguration(after = JdbcTemplateAutoConfiguration.class) @ConditionalOnClass({ MariaDBVectorStore.class, DataSource.class, JdbcTemplate.class }) @EnableConfigurationProperties(org.springframework.ai.vectorstore.mariadb.autoconfigure.MariaDbStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.MARIADB, + matchIfMissing = true) public class MariaDbStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java index f21b2ef2b..44217bd06 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mariadb/src/test/java/org/springframework/ai/vectorstore/mariadb/autoconfigure/MariaDbStoreAutoConfigurationIT.java @@ -25,6 +25,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.observation.conventions.VectorStoreProvider; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; +import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -179,6 +180,33 @@ public class MariaDbStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(MariaDbStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(MariaDBVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(MariaDbStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(MariaDBVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsMariaDB() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=mariadb").run(context -> { + assertThat(context.getBeansOfType(MariaDbStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(MariaDBVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/main/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/main/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfiguration.java index 6ba8d36f6..88830487e 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/main/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/main/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfiguration.java @@ -27,12 +27,14 @@ import io.milvus.param.MetricType; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.milvus.MilvusVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.util.StringUtils; @@ -48,6 +50,8 @@ import org.springframework.util.StringUtils; @AutoConfiguration @ConditionalOnClass({ MilvusVectorStore.class, EmbeddingModel.class }) @EnableConfigurationProperties({ MilvusServiceClientProperties.class, MilvusVectorStoreProperties.class }) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.MILVUS, + matchIfMissing = true) public class MilvusVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/test/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/test/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfigurationIT.java index 1b2051b29..a366447d3 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/test/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-milvus/src/test/java/org/springframework/ai/vectorstore/milvus/autoconfigure/MilvusVectorStoreAutoConfigurationIT.java @@ -33,6 +33,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.ai.vectorstore.milvus.MilvusVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -163,6 +164,40 @@ public class MilvusVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(MilvusVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(MilvusVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner + .withPropertyValues("spring.ai.vectorstore.milvus.client.host=" + milvus.getHost(), + "spring.ai.vectorstore.milvus.client.port=" + milvus.getMappedPort(19530)) + .run(context -> { + assertThat(context.getBeansOfType(MilvusVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(MilvusVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsMilvus() { + this.contextRunner + .withPropertyValues("spring.ai.vectorstore.milvus.client.host=" + milvus.getHost(), + "spring.ai.vectorstore.milvus.client.port=" + milvus.getMappedPort(19530)) + .withPropertyValues("spring.ai.vectorstore.type=milvus") + .run(context -> { + assertThat(context.getBeansOfType(MilvusVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(MilvusVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/main/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/main/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfiguration.java index 9e1bd19e5..4aa8aeb7c 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/main/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/main/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfiguration.java @@ -24,12 +24,14 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.mongodb.atlas.MongoDBAtlasVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.core.convert.converter.Converter; @@ -51,6 +53,8 @@ import org.springframework.util.StringUtils; @AutoConfiguration @ConditionalOnClass({ MongoDBAtlasVectorStore.class, EmbeddingModel.class, MongoTemplate.class }) @EnableConfigurationProperties(MongoDBAtlasVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.MONGODB_ATLAS, + matchIfMissing = true) public class MongoDBAtlasVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java index cdbdd8481..17351f5d5 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-mongodb-atlas/src/test/java/org/springframework/ai/vectorstore/mongodb/autoconfigure/MongoDBAtlasVectorStoreAutoConfigurationIT.java @@ -35,6 +35,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder; +import org.springframework.ai.vectorstore.mongodb.atlas.MongoDBAtlasVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; @@ -162,6 +163,33 @@ class MongoDBAtlasVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(MongoDBAtlasVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(MongoDBAtlasVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(MongoDBAtlasVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(MongoDBAtlasVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsMongodbAtlas() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=mongodb-atlas").run(context -> { + assertThat(context.getBeansOfType(MongoDBAtlasVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(MongoDBAtlasVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java index 9ee3b7d81..a01cd031a 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/main/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfiguration.java @@ -22,12 +22,14 @@ import org.neo4j.driver.Driver; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.neo4j.Neo4jVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -43,6 +45,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration(after = Neo4jAutoConfiguration.class) @ConditionalOnClass({ Neo4jVectorStore.class, EmbeddingModel.class, Driver.class }) @EnableConfigurationProperties({ Neo4jVectorStoreProperties.class }) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.NEO4J, + matchIfMissing = true) public class Neo4jVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java index a42134544..88437ece6 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-neo4j/src/test/java/org/springframework/ai/vectorstore/neo4j/autoconfigure/Neo4jVectorStoreAutoConfigurationIT.java @@ -34,6 +34,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil; import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.ai.vectorstore.neo4j.Neo4jVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; @@ -114,6 +115,33 @@ public class Neo4jVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(Neo4jVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(Neo4jVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(Neo4jVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(Neo4jVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsNeo4j() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=neo4j").run(context -> { + assertThat(context.getBeansOfType(Neo4jVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(Neo4jVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java index 1574be955..91e946eef 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/main/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfiguration.java @@ -40,6 +40,7 @@ import software.amazon.awssdk.regions.Region; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; @@ -47,6 +48,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -55,6 +57,8 @@ import org.springframework.util.StringUtils; @AutoConfiguration @ConditionalOnClass({ OpenSearchVectorStore.class, EmbeddingModel.class, OpenSearchClient.class }) @EnableConfigurationProperties(OpenSearchVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.OPENSEARCH, + matchIfMissing = true) public class OpenSearchVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/test/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/test/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfigurationIT.java index 33044f011..2c40806b0 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/test/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-opensearch/src/test/java/org/springframework/ai/vectorstore/opensearch/autoconfigure/OpenSearchVectorStoreAutoConfigurationIT.java @@ -37,6 +37,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.observation.conventions.VectorStoreProvider; import org.springframework.ai.test.vectorstore.ObservationTestUtil; import org.springframework.ai.transformers.TransformersEmbeddingModel; +import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; @@ -142,6 +143,33 @@ class OpenSearchVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(OpenSearchVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(OpenSearchVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(OpenSearchVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(OpenSearchVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsOpensearch() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=opensearch").run(context -> { + assertThat(context.getBeansOfType(OpenSearchVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(OpenSearchVectorStore.class); + }); + } + private String getText(String uri) { var resource = new DefaultResourceLoader().getResource(uri); try { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java index a9a3d322d..82c71c170 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/main/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfiguration.java @@ -23,12 +23,14 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.oracle.OracleVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -45,6 +47,8 @@ import org.springframework.jdbc.core.JdbcTemplate; @AutoConfiguration(after = JdbcTemplateAutoConfiguration.class) @ConditionalOnClass({ OracleVectorStore.class, DataSource.class, JdbcTemplate.class }) @EnableConfigurationProperties(OracleVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.ORACLE, + matchIfMissing = true) public class OracleVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java index 97bb9b6f6..1e1261389 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-oracle/src/test/java/org/springframework/ai/vectorstore/oracle/autoconfigure/OracleVectorStoreAutoConfigurationIT.java @@ -36,6 +36,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; +import org.springframework.ai.vectorstore.oracle.OracleVectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; @@ -124,6 +125,33 @@ public class OracleVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(OracleVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(OracleVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(OracleVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(OracleVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsOracle() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=oracle").run(context -> { + assertThat(context.getBeansOfType(OracleVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(OracleVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java index bcc8ba6ca..d901d96b8 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java @@ -23,12 +23,14 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.pgvector.PgVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -45,6 +47,8 @@ import org.springframework.jdbc.core.JdbcTemplate; @AutoConfiguration(after = JdbcTemplateAutoConfiguration.class) @ConditionalOnClass({ PgVectorStore.class, DataSource.class, JdbcTemplate.class }) @EnableConfigurationProperties(PgVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.PGVECTOR, + matchIfMissing = true) public class PgVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java index 714463b87..0db699138 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/test/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfigurationIT.java @@ -34,6 +34,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.observation.conventions.VectorStoreProvider; import org.springframework.ai.test.vectorstore.ObservationTestUtil; import org.springframework.ai.transformers.TransformersEmbeddingModel; +import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.pgvector.PgVectorStore; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; @@ -163,6 +164,33 @@ public class PgVectorStoreAutoConfigurationIT { .run(context -> assertThat(isFullyQualifiedTableExists(context, schemaName, tableName)).isFalse()); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(PgVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(PgVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(PgVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(PgVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsPgvector() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=pgvector").run(context -> { + assertThat(context.getBeansOfType(PgVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(PgVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/main/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/main/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfiguration.java index e8683d78d..bfa56985f 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/main/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/main/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfiguration.java @@ -21,12 +21,14 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -39,6 +41,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass({ PineconeVectorStore.class, EmbeddingModel.class }) @EnableConfigurationProperties(PineconeVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.PINECONE, + matchIfMissing = true) public class PineconeVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/test/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/test/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfigurationIT.java index 1a7495bf7..8f52cc085 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/test/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pinecone/src/test/java/org/springframework/ai/vectorstore/pinecone/autoconfigure/PineconeVectorStoreAutoConfigurationIT.java @@ -35,6 +35,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.observation.conventions.VectorStoreProvider; import org.springframework.ai.test.vectorstore.ObservationTestUtil; import org.springframework.ai.transformers.TransformersEmbeddingModel; +import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; @@ -131,6 +132,33 @@ public class PineconeVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(PineconeVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(PineconeVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(PineconeVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(PineconeVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsPinecone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=pinecone").run(context -> { + assertThat(context.getBeansOfType(PineconeVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(PineconeVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/main/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/main/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfiguration.java index b01143a9a..ae18b85c3 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/main/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/main/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfiguration.java @@ -23,12 +23,14 @@ import io.qdrant.client.QdrantGrpcClient; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -44,6 +46,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass({ QdrantVectorStore.class, EmbeddingModel.class }) @EnableConfigurationProperties(QdrantVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.QDRANT, + matchIfMissing = true) public class QdrantVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/test/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/test/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfigurationIT.java index 764c94a33..bc098fe66 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/test/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-qdrant/src/test/java/org/springframework/ai/vectorstore/qdrant/autoconfigure/QdrantVectorStoreAutoConfigurationIT.java @@ -35,6 +35,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; +import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -114,6 +115,33 @@ public class QdrantVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(QdrantVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(QdrantVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(QdrantVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(QdrantVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsQdrant() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=qdrant").run(context -> { + assertThat(context.getBeansOfType(QdrantVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(QdrantVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java index 57ffda835..2a23a1af4 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java @@ -25,6 +25,7 @@ import redis.clients.jedis.JedisPooled; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.redis.RedisVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; @@ -32,6 +33,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -49,6 +51,8 @@ import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; @ConditionalOnClass({ JedisPooled.class, JedisConnectionFactory.class, RedisVectorStore.class, EmbeddingModel.class }) @ConditionalOnBean(JedisConnectionFactory.class) @EnableConfigurationProperties(RedisVectorStoreProperties.class) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.REDIS, + matchIfMissing = true) public class RedisVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java index bae82f42c..e92f7481c 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java @@ -34,6 +34,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; +import org.springframework.ai.vectorstore.redis.RedisVectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -106,6 +107,33 @@ class RedisVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(RedisVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(RedisVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(RedisVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(RedisVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsRedis() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=redis").run(context -> { + assertThat(context.getBeansOfType(RedisVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(RedisVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/main/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/main/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfiguration.java index 8822ce57e..41e8d048f 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/main/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/main/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfiguration.java @@ -28,12 +28,14 @@ import org.typesense.resources.Node; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.typesense.TypesenseVectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -47,6 +49,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass({ TypesenseVectorStore.class, EmbeddingModel.class }) @EnableConfigurationProperties({ TypesenseServiceClientProperties.class, TypesenseVectorStoreProperties.class }) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.TYPESENSE, + matchIfMissing = true) public class TypesenseVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/test/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/test/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfigurationIT.java index a3213b05d..271f043a5 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/test/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-typesense/src/test/java/org/springframework/ai/vectorstore/typesense/autoconfigure/TypesenseVectorStoreAutoConfigurationIT.java @@ -34,6 +34,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; +import org.springframework.ai.vectorstore.typesense.TypesenseVectorStore; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -109,6 +110,33 @@ public class TypesenseVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(TypesenseVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(TypesenseVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(TypesenseVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(TypesenseVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsTypesense() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=typesense").run(context -> { + assertThat(context.getBeansOfType(TypesenseVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(TypesenseVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/main/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/main/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfiguration.java index a7d1453a1..bffd15045 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/main/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/main/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfiguration.java @@ -25,12 +25,14 @@ import io.weaviate.client.v1.auth.exception.AuthException; import org.springframework.ai.embedding.BatchingStrategy; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy; +import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -44,6 +46,8 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass({ EmbeddingModel.class, WeaviateVectorStore.class }) @EnableConfigurationProperties({ WeaviateVectorStoreProperties.class }) +@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.WEAVIATE, + matchIfMissing = true) public class WeaviateVectorStoreAutoConfiguration { @Bean diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/test/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/test/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfigurationIT.java index eddd4ba80..8e01aade5 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/test/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/test/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfigurationIT.java @@ -33,6 +33,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext; +import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore; import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore.MetadataField; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -146,6 +147,33 @@ public class WeaviateVectorStoreAutoConfigurationIT { }); } + @Test + public void autoConfigurationDisabledWhenTypeIsNone() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> { + assertThat(context.getBeansOfType(WeaviateVectorStoreProperties.class)).isEmpty(); + assertThat(context.getBeansOfType(WeaviateVectorStore.class)).isEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isEmpty(); + }); + } + + @Test + public void autoConfigurationEnabledByDefault() { + this.contextRunner.run(context -> { + assertThat(context.getBeansOfType(WeaviateVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(WeaviateVectorStore.class); + }); + } + + @Test + public void autoConfigurationEnabledWhenTypeIsWeaviate() { + this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=weaviate").run(context -> { + assertThat(context.getBeansOfType(WeaviateVectorStoreProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty(); + assertThat(context.getBean(VectorStore.class)).isInstanceOf(WeaviateVectorStore.class); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java new file mode 100644 index 000000000..1dfc06f99 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SpringAIVectorStoreTypes.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023-2025 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.ai.vectorstore; + +public class SpringAIVectorStoreTypes { + + public static final String VECTOR_STORE_PREFIX = "spring.ai.vectorstore"; + + public static final String TYPE = VECTOR_STORE_PREFIX + ".type"; + + public static final String AZURE = "azure"; + + public static final String AZURE_COSMOS_DB = "azure-cosmos-db"; + + public static final String CASSANDRA = "cassandra"; + + public static final String CHROMA = "chroma"; + + public static final String ELASTICSEARCH = "elasticsearch"; + + public static final String GEMFIRE = "gemfire"; + + public static final String HANADB = "hanadb"; + + public static final String MARIADB = "mariadb"; + + public static final String MILVUS = "milvus"; + + public static final String MONGODB_ATLAS = "mongodb-atlas"; + + public static final String NEO4J = "neo4j"; + + public static final String OPENSEARCH = "opensearch"; + + public static final String ORACLE = "oracle"; + + public static final String PGVECTOR = "pgvector"; + + public static final String PINECONE = "pinecone"; + + public static final String QDRANT = "qdrant"; + + public static final String REDIS = "redis"; + + public static final String TYPESENSE = "typesense"; + + public static final String WEAVIATE = "weaviate"; + +}