Align JdbcChatMemoryRepositoryProperties with other modules in Spring Boot
Such as `BatchProperties.Jdbc`, `IntegrationProperties.Jdbc`, `JdbcSessionProperties` and `QuartzProperties.Jdbc` 1. Reuse Spring Boot's `DatabaseInitializationMode` 2. Allow to customize platform 3. add `OnJdbcChatMemoryRepositoryDatasourceInitializationCondition` for `JdbcChatMemoryRepositorySchemaInitializer` Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
This commit is contained in:
committed by
Ilayaperumal Gopinathan
parent
a6bb325b62
commit
e10fbde7a1
@@ -18,9 +18,6 @@ package org.springframework.ai.model.chat.memory.repository.jdbc.autoconfigure;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.ai.chat.memory.jdbc.JdbcChatMemoryDialect;
|
||||
import org.springframework.ai.chat.memory.jdbc.JdbcChatMemoryRepository;
|
||||
import org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration;
|
||||
@@ -28,13 +25,16 @@ 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.jdbc.JdbcTemplateAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* @author Jonathan Leijendekker
|
||||
* @author Thomas Vitale
|
||||
* @author Yanming Zhou
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@AutoConfiguration(after = JdbcTemplateAutoConfiguration.class, before = ChatMemoryAutoConfiguration.class)
|
||||
@@ -51,9 +51,19 @@ public class JdbcChatMemoryRepositoryAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(OnJdbcChatMemoryRepositoryDatasourceInitializationCondition.class)
|
||||
JdbcChatMemoryRepositorySchemaInitializer jdbcChatMemoryScriptDatabaseInitializer(DataSource dataSource,
|
||||
JdbcChatMemoryRepositoryProperties properties) {
|
||||
return new JdbcChatMemoryRepositorySchemaInitializer(dataSource, properties);
|
||||
}
|
||||
|
||||
static class OnJdbcChatMemoryRepositoryDatasourceInitializationCondition extends OnDatabaseInitializationCondition {
|
||||
|
||||
OnJdbcChatMemoryRepositoryDatasourceInitializationCondition() {
|
||||
super("Jdbc Chat Memory Repository",
|
||||
JdbcChatMemoryRepositoryProperties.CONFIG_PREFIX + ".initialize-schema");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package org.springframework.ai.model.chat.memory.repository.jdbc.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationMode;
|
||||
|
||||
/**
|
||||
* @author Jonathan Leijendekker
|
||||
* @author Thomas Vitale
|
||||
* @author Yanming Zhou
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ConfigurationProperties(JdbcChatMemoryRepositoryProperties.CONFIG_PREFIX)
|
||||
@@ -28,6 +30,8 @@ public class JdbcChatMemoryRepositoryProperties {
|
||||
|
||||
public static final String CONFIG_PREFIX = "spring.ai.chat.memory.repository.jdbc";
|
||||
|
||||
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/ai/chat/memory/jdbc/schema-@@platform@@.sql";
|
||||
|
||||
/**
|
||||
* Whether to initialize the schema on startup. Values: embedded, always, never.
|
||||
* Default is embedded.
|
||||
@@ -38,7 +42,13 @@ public class JdbcChatMemoryRepositoryProperties {
|
||||
* Locations of schema (DDL) scripts. Supports comma-separated list. Default is
|
||||
* classpath:org/springframework/ai/chat/memory/jdbc/schema-@@platform@@.sql
|
||||
*/
|
||||
private String schema = "classpath:org/springframework/ai/chat/memory/jdbc/schema-@@platform@@.sql";
|
||||
private String schema = DEFAULT_SCHEMA_LOCATION;
|
||||
|
||||
/**
|
||||
* Platform to use in initialization scripts if the @@platform@@ placeholder is used.
|
||||
* Auto-detected by default.
|
||||
*/
|
||||
private String platform;
|
||||
|
||||
public DatabaseInitializationMode getInitializeSchema() {
|
||||
return this.initializeSchema;
|
||||
@@ -48,6 +58,14 @@ public class JdbcChatMemoryRepositoryProperties {
|
||||
this.initializeSchema = initializeSchema;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public void setPlatform(String platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
public String getSchema() {
|
||||
return this.schema;
|
||||
}
|
||||
@@ -56,23 +74,4 @@ public class JdbcChatMemoryRepositoryProperties {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public enum DatabaseInitializationMode {
|
||||
|
||||
/**
|
||||
* Always initialize the database.
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Only initialize an embedded database.
|
||||
*/
|
||||
EMBEDDED,
|
||||
|
||||
/**
|
||||
* Never initialize the database.
|
||||
*/
|
||||
NEVER
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
|
||||
import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationMode;
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -30,12 +29,11 @@ import org.springframework.util.StringUtils;
|
||||
* Performs database initialization for the JDBC Chat Memory Repository.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author Yanming Zhou
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class JdbcChatMemoryRepositorySchemaInitializer extends DataSourceScriptDatabaseInitializer {
|
||||
|
||||
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/ai/chat/memory/jdbc/schema-@@platform@@.sql";
|
||||
|
||||
JdbcChatMemoryRepositorySchemaInitializer(DataSource dataSource, JdbcChatMemoryRepositoryProperties properties) {
|
||||
super(dataSource, getSettings(dataSource, properties));
|
||||
}
|
||||
@@ -43,50 +41,19 @@ class JdbcChatMemoryRepositorySchemaInitializer extends DataSourceScriptDatabase
|
||||
static DatabaseInitializationSettings getSettings(DataSource dataSource,
|
||||
JdbcChatMemoryRepositoryProperties properties) {
|
||||
var settings = new DatabaseInitializationSettings();
|
||||
|
||||
// Determine schema locations
|
||||
String schemaProp = properties.getSchema();
|
||||
List<String> schemaLocations;
|
||||
PlatformPlaceholderDatabaseDriverResolver resolver = new PlatformPlaceholderDatabaseDriverResolver();
|
||||
try {
|
||||
String url = dataSource.getConnection().getMetaData().getURL().toLowerCase();
|
||||
if (url.contains("hsqldb")) {
|
||||
schemaLocations = List.of("classpath:org/springframework/ai/chat/memory/jdbc/schema-hsqldb.sql");
|
||||
}
|
||||
else if (StringUtils.hasText(schemaProp)) {
|
||||
schemaLocations = resolver.resolveAll(dataSource, schemaProp);
|
||||
}
|
||||
else {
|
||||
schemaLocations = resolver.resolveAll(dataSource, DEFAULT_SCHEMA_LOCATION);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// fallback to default
|
||||
if (StringUtils.hasText(schemaProp)) {
|
||||
schemaLocations = resolver.resolveAll(dataSource, schemaProp);
|
||||
}
|
||||
else {
|
||||
schemaLocations = resolver.resolveAll(dataSource, DEFAULT_SCHEMA_LOCATION);
|
||||
}
|
||||
}
|
||||
settings.setSchemaLocations(schemaLocations);
|
||||
|
||||
// Determine initialization mode
|
||||
JdbcChatMemoryRepositoryProperties.DatabaseInitializationMode init = properties.getInitializeSchema();
|
||||
DatabaseInitializationMode mode;
|
||||
if (JdbcChatMemoryRepositoryProperties.DatabaseInitializationMode.ALWAYS.equals(init)) {
|
||||
mode = DatabaseInitializationMode.ALWAYS;
|
||||
}
|
||||
else if (JdbcChatMemoryRepositoryProperties.DatabaseInitializationMode.NEVER.equals(init)) {
|
||||
mode = DatabaseInitializationMode.NEVER;
|
||||
}
|
||||
else {
|
||||
// embedded or default
|
||||
mode = DatabaseInitializationMode.EMBEDDED;
|
||||
}
|
||||
settings.setMode(mode);
|
||||
settings.setSchemaLocations(resolveSchemaLocations(dataSource, properties));
|
||||
settings.setMode(properties.getInitializeSchema());
|
||||
settings.setContinueOnError(true);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static List<String> resolveSchemaLocations(DataSource dataSource,
|
||||
JdbcChatMemoryRepositoryProperties properties) {
|
||||
PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver();
|
||||
if (StringUtils.hasText(properties.getPlatform())) {
|
||||
return platformResolver.resolveAll(properties.getPlatform(), properties.getSchema());
|
||||
}
|
||||
return platformResolver.resolveAll(dataSource, properties.getSchema());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Jonathan Leijendekker
|
||||
* @author Thomas Vitale
|
||||
* @author Linar Abzaltdinov
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
class JdbcChatMemoryPostgresqlAutoConfigurationIT {
|
||||
|
||||
@@ -49,14 +50,14 @@ class JdbcChatMemoryPostgresqlAutoConfigurationIT {
|
||||
@Test
|
||||
void jdbcChatMemoryScriptDatabaseInitializer_shouldBeLoaded() {
|
||||
this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=always")
|
||||
.run(context -> assertThat(context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue());
|
||||
.run(context -> assertThat(context).hasBean("jdbcChatMemoryScriptDatabaseInitializer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jdbcChatMemoryScriptDatabaseInitializer_shouldNotRunSchemaInit() {
|
||||
this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=never")
|
||||
.run(context -> {
|
||||
assertThat(context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue();
|
||||
assertThat(context).doesNotHaveBean("jdbcChatMemoryScriptDatabaseInitializer");
|
||||
// Optionally, check that the schema is not initialized (could check table
|
||||
// absence if needed)
|
||||
});
|
||||
@@ -65,7 +66,7 @@ class JdbcChatMemoryPostgresqlAutoConfigurationIT {
|
||||
@Test
|
||||
void initializeSchemaEmbeddedDefault() {
|
||||
this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=embedded")
|
||||
.run(context -> assertThat(context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue());
|
||||
.run(context -> assertThat(context).hasBean("jdbcChatMemoryScriptDatabaseInitializer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.ai.model.chat.memory.repository.jdbc.autoconfigure;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.sql.init.DatabaseInitializationMode;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
@@ -28,16 +30,14 @@ class JdbcChatMemoryRepositoryPropertiesTests {
|
||||
@Test
|
||||
void defaultValues() {
|
||||
var props = new JdbcChatMemoryRepositoryProperties();
|
||||
assertThat(props.getInitializeSchema())
|
||||
.isEqualTo(JdbcChatMemoryRepositoryProperties.DatabaseInitializationMode.EMBEDDED);
|
||||
assertThat(props.getInitializeSchema()).isEqualTo(DatabaseInitializationMode.EMBEDDED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customValues() {
|
||||
var props = new JdbcChatMemoryRepositoryProperties();
|
||||
props.setInitializeSchema(JdbcChatMemoryRepositoryProperties.DatabaseInitializationMode.NEVER);
|
||||
assertThat(props.getInitializeSchema())
|
||||
.isEqualTo(JdbcChatMemoryRepositoryProperties.DatabaseInitializationMode.NEVER);
|
||||
props.setInitializeSchema(DatabaseInitializationMode.NEVER);
|
||||
assertThat(props.getInitializeSchema()).isEqualTo(DatabaseInitializationMode.NEVER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,21 +52,21 @@ class JdbcChatMemorySqlServerAutoConfigurationIT {
|
||||
@Test
|
||||
void jdbcChatMemoryScriptDatabaseInitializer_shouldBeLoaded() {
|
||||
this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=always")
|
||||
.run(context -> assertThat(context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue());
|
||||
.run(context -> assertThat(context).hasBean("jdbcChatMemoryScriptDatabaseInitializer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jdbcChatMemoryScriptDatabaseInitializer_shouldNotRunSchemaInit() {
|
||||
this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=never")
|
||||
.run(context -> {
|
||||
assertThat(context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue();
|
||||
assertThat(context).doesNotHaveBean("jdbcChatMemoryScriptDatabaseInitializer");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void initializeSchemaEmbeddedDefault() {
|
||||
this.contextRunner.withPropertyValues("spring.ai.chat.memory.repository.jdbc.initialize-schema=embedded")
|
||||
.run(context -> assertThat(context.containsBean("jdbcChatMemoryScriptDatabaseInitializer")).isTrue());
|
||||
.run(context -> assertThat(context).hasBean("jdbcChatMemoryScriptDatabaseInitializer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user