Auto-discover ClickHouse migration files instead of hardcoded list
All checks were successful
CI / build (push) Successful in 1m11s
CI / docker (push) Successful in 41s
CI / deploy (push) Successful in 29s

Replace the static SCHEMA_FILES array with classpath pattern matching
(classpath:clickhouse/*.sql). Migration files are discovered and sorted
by filename, so adding a new numbered .sql file is all that's needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-14 16:26:33 +01:00
parent 9f9e677103
commit dbf53aa8e8

View File

@@ -4,12 +4,15 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import jakarta.annotation.PostConstruct;
import javax.sql.DataSource;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.Collectors;
/**
@@ -20,16 +23,15 @@ import java.util.stream.Collectors;
* <p>
* The ClickHouse container's {@code CLICKHOUSE_DB} env var creates the database;
* this class creates the tables within it.
* <p>
* Migration files are discovered automatically from {@code classpath:clickhouse/*.sql}
* and executed in filename order (numeric prefix sort).
*/
@Configuration
public class ClickHouseConfig {
private static final Logger log = LoggerFactory.getLogger(ClickHouseConfig.class);
private static final String[] SCHEMA_FILES = {
"clickhouse/01-schema.sql", "clickhouse/02-search-columns.sql",
"clickhouse/03-users.sql", "clickhouse/04-oidc-config.sql",
"clickhouse/05-oidc-auto-signup.sql", "clickhouse/06-oidc-display-name-claim.sql"
};
private static final String MIGRATION_PATTERN = "classpath:clickhouse/*.sql";
private final DataSource dataSource;
@@ -45,25 +47,34 @@ public class ClickHouseConfig {
@PostConstruct
void initSchema() {
var jdbc = new JdbcTemplate(dataSource);
for (String schemaFile : SCHEMA_FILES) {
try {
String sql = new ClassPathResource(schemaFile).getContentAsString(StandardCharsets.UTF_8);
// Strip comment lines before splitting — a statement preceded by
// comment lines would otherwise be skipped entirely.
String stripped = sql.lines()
.filter(line -> !line.trim().startsWith("--"))
.collect(Collectors.joining("\n"));
for (String statement : stripped.split(";")) {
String trimmed = statement.trim();
if (!trimmed.isEmpty()) {
jdbc.execute(trimmed);
try {
Resource[] resources = new PathMatchingResourcePatternResolver()
.getResources(MIGRATION_PATTERN);
Arrays.sort(resources, Comparator.comparing(Resource::getFilename));
for (Resource resource : resources) {
String filename = resource.getFilename();
try {
String sql = resource.getContentAsString(StandardCharsets.UTF_8);
String stripped = sql.lines()
.filter(line -> !line.trim().startsWith("--"))
.collect(Collectors.joining("\n"));
for (String statement : stripped.split(";")) {
String trimmed = statement.trim();
if (!trimmed.isEmpty()) {
jdbc.execute(trimmed);
}
}
log.info("Applied schema: {}", filename);
} catch (Exception e) {
log.error("Failed to apply schema: {}", filename, e);
throw new RuntimeException("Schema initialization failed: " + filename, e);
}
log.info("Applied schema: {}", schemaFile);
} catch (Exception e) {
log.error("Failed to apply schema: {}", schemaFile, e);
throw new RuntimeException("Schema initialization failed: " + schemaFile, e);
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Failed to discover migration files", e);
}
}
}