Demonstrate Schema Generation in Spring Data Jdbc.
This provides the source examples for the upcoming blog post. Closes #667
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
<module>caching</module>
|
||||
<module>idgeneration</module>
|
||||
<module>selectiveupdate</module>
|
||||
<module>schema-generation</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
1
jdbc/howto/schema-generation/.gitignore
vendored
Normal file
1
jdbc/howto/schema-generation/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
cs-*.yaml
|
||||
5
jdbc/howto/schema-generation/README.adoc
Normal file
5
jdbc/howto/schema-generation/README.adoc
Normal file
@@ -0,0 +1,5 @@
|
||||
== Spring Data JDBC How To Generate the Database Schema.
|
||||
|
||||
Spring Data JDBC offers an API to generate Liquibase Changesets from your domain model and optionally an existing database.
|
||||
|
||||
This project demonstrates how to do this.
|
||||
33
jdbc/howto/schema-generation/pom.xml
Normal file
33
jdbc/howto/schema-generation/pom.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-data-jdbc-how-to-schema-generation</artifactId>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.examples</groupId>
|
||||
<artifactId>spring-data-jdbc-how-to</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data JDBC - How to do schema generation</name>
|
||||
<description>Sample project for Spring Data JDBC demonstrating how it can be used to generate and update your
|
||||
schema.
|
||||
</description>
|
||||
<url>https://projects.spring.io/spring-data-jdbc</url>
|
||||
<inceptionYear>2023</inceptionYear>
|
||||
|
||||
<properties>
|
||||
<spring-data-bom.version>2023.1.0-M2</spring-data-bom.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.liquibase</groupId>
|
||||
<artifactId>liquibase-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2023 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 example.springdata.jdbc.howto.caching;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
|
||||
|
||||
/**
|
||||
* Entity we use as a fixture for demonstrating Schema Generation.
|
||||
* See SchemaGenerationTest in the test directory for the interesting stuff.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 3.2
|
||||
*/
|
||||
@Table
|
||||
class Minion {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Name
|
||||
String name;
|
||||
|
||||
Minion(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2023 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 example.springdata.jdbc.howto.caching;
|
||||
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Annotation to mark a property as a Name which should have a very specify database type.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@Varchar(20)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Name {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2023 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 example.springdata.jdbc.howto.caching;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
|
||||
/**
|
||||
* Boot application that we use as a fixture for demonstrating Schema Generation.
|
||||
* See SchemaGenerationTest in the test directory for the interesting stuff.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 3.2
|
||||
*/
|
||||
@EnableCaching
|
||||
@SpringBootApplication
|
||||
class SchemaGenerationExampleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SchemaGenerationExampleApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2023 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 example.springdata.jdbc.howto.caching;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Marks a property as to be represented by a VARCHAR database type.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Varchar {
|
||||
|
||||
/**
|
||||
* the size of the varchar.
|
||||
*/
|
||||
int value();
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Disable Liquibase when you don't have changesets configured yet.
|
||||
# spring.liquibase.enabled=false
|
||||
@@ -0,0 +1,32 @@
|
||||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: '1692725820135'
|
||||
author: Spring Data Relational
|
||||
objectQuotingStrategy: LEGACY
|
||||
changes:
|
||||
- createTable:
|
||||
columns:
|
||||
- column:
|
||||
autoIncrement: true
|
||||
constraints:
|
||||
nullable: true
|
||||
primaryKey: true
|
||||
name: id
|
||||
type: BIGINT
|
||||
- column:
|
||||
constraints:
|
||||
nullable: true
|
||||
name: firstname
|
||||
type: VARCHAR(255 BYTE)
|
||||
- column:
|
||||
constraints:
|
||||
nullable: true
|
||||
name: lastname
|
||||
type: VARCHAR(255 BYTE)
|
||||
- column:
|
||||
constraints:
|
||||
nullable: true
|
||||
name: special
|
||||
type: VARCHAR(255 BYTE)
|
||||
tableName: minion
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2023 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 example.springdata.jdbc.howto.caching;
|
||||
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.core.HsqlDatabase;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.exception.LiquibaseException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.data.jdbc.core.mapping.schema.DefaultSqlTypeMapping;
|
||||
import org.springframework.data.jdbc.core.mapping.schema.LiquibaseChangeSetWriter;
|
||||
import org.springframework.data.jdbc.core.mapping.schema.SqlTypeMapping;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Example code demonstrating how to use the Schema Generation Feature.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 3.2
|
||||
*/
|
||||
@SpringBootTest
|
||||
class SchemaGenerationTest {
|
||||
|
||||
@Autowired
|
||||
RelationalMappingContext context;
|
||||
|
||||
@Autowired
|
||||
DataSource ds;
|
||||
|
||||
@Test
|
||||
void minimumExample() throws IOException {
|
||||
|
||||
// the change set will get appended, so we delete any pre existing file.
|
||||
new File("cs-minimum.yaml").delete();
|
||||
|
||||
context.setInitialEntitySet(Collections.singleton(Minion.class));
|
||||
LiquibaseChangeSetWriter writer = new LiquibaseChangeSetWriter(context);
|
||||
|
||||
writer.writeChangeSet(new FileSystemResource("cs-minimum.yaml"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void diffing() {
|
||||
|
||||
// the change set will get appended, so we delete any pre existing file.
|
||||
new File("cs-diff.yaml").delete();
|
||||
|
||||
context.setInitialEntitySet(Collections.singleton(Minion.class));
|
||||
LiquibaseChangeSetWriter writer = new LiquibaseChangeSetWriter(context);
|
||||
|
||||
// drop unused columns
|
||||
writer.setDropColumnFilter((table, column) -> !column.equalsIgnoreCase("special"));
|
||||
|
||||
// for comparison with existing schema
|
||||
try (Database db = new HsqlDatabase()) {
|
||||
|
||||
db.setConnection(new JdbcConnection(ds.getConnection()));
|
||||
|
||||
writer.writeChangeSet(new FileSystemResource("cs-diff.yaml"), db);
|
||||
|
||||
} catch (IOException | SQLException | LiquibaseException e) {
|
||||
throw new RuntimeException("Changeset generation failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizingTypes() throws IOException {
|
||||
|
||||
// the change set will get appended, so we delete any pre existing file.
|
||||
new File("cs-custom.yaml").delete();
|
||||
|
||||
context.setInitialEntitySet(Collections.singleton(Minion.class));
|
||||
LiquibaseChangeSetWriter writer = new LiquibaseChangeSetWriter(context);
|
||||
|
||||
writer.setSqlTypeMapping(((SqlTypeMapping) property -> {
|
||||
if (property.getName().equalsIgnoreCase("name")) {
|
||||
return "VARCHAR(500)";
|
||||
}
|
||||
return null;
|
||||
}).and(new DefaultSqlTypeMapping()));
|
||||
|
||||
writer.writeChangeSet(new FileSystemResource("cs-custom.yaml"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizingTypesUsingAnnotations() throws IOException {
|
||||
|
||||
// the change set will get appended, so we delete any pre existing file.
|
||||
new File("cs-annotation.yaml").delete();
|
||||
|
||||
context.setInitialEntitySet(Collections.singleton(Minion.class));
|
||||
LiquibaseChangeSetWriter writer = new LiquibaseChangeSetWriter(context);
|
||||
|
||||
writer.setSqlTypeMapping(((SqlTypeMapping) property -> {
|
||||
|
||||
if (!property.getType().equals(String.class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// findAnnotation will find meta annotations
|
||||
Varchar varchar = property.findAnnotation(Varchar.class);
|
||||
int value = varchar.value();
|
||||
|
||||
if (varchar == null) {
|
||||
return null;
|
||||
}
|
||||
return "VARCHAR(" +
|
||||
varchar.value() +
|
||||
")";
|
||||
|
||||
}).and(new DefaultSqlTypeMapping()));
|
||||
|
||||
writer.writeChangeSet(new FileSystemResource("cs-annotation.yaml"));
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user