diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml
index e0d059aec0..d2bb25024f 100644
--- a/spring-data-jdbc/pom.xml
+++ b/spring-data-jdbc/pom.xml
@@ -7,7 +7,6 @@
spring-data-jdbc
3.1.0-756-SNAPSHOT
-
Spring Data JDBC
Spring Data module for JDBC repositories.
https://projects.spring.io/spring-data-jdbc
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java
index c6712a4c9a..4a20ba7080 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalMappingContext.java
@@ -22,6 +22,8 @@
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
+import java.util.Iterator;
+
/**
* {@link MappingContext} implementation.
*
@@ -101,5 +103,4 @@ protected RelationalPersistentProperty createPersistentProperty(Property propert
public NamingStrategy getNamingStrategy() {
return this.namingStrategy;
}
-
}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/BaseTypeMapper.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/BaseTypeMapper.java
new file mode 100644
index 0000000000..9e8f5335e0
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/BaseTypeMapper.java
@@ -0,0 +1,34 @@
+/*
+ * 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 org.springframework.data.relational.core.mapping.schemasqlgeneration;
+
+import java.util.HashMap;
+
+public class BaseTypeMapper {
+
+ final HashMap,String> mapClassToDatabaseType = new HashMap,String>();
+
+ public BaseTypeMapper() {
+ mapClassToDatabaseType.put(String.class, "VARCHAR(255)");
+ mapClassToDatabaseType.put(Boolean.class, "TINYINT");
+ mapClassToDatabaseType.put(Double.class, "DOUBLE");
+ mapClassToDatabaseType.put(Float.class, "FLOAT");
+ mapClassToDatabaseType.put(Integer.class, "INT");
+ }
+ public String databaseTypeFromClass(Class> type) {
+ return mapClassToDatabaseType.get(type);
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/ColumnModel.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/ColumnModel.java
new file mode 100644
index 0000000000..18cd0d12c1
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/ColumnModel.java
@@ -0,0 +1,58 @@
+/*
+ * 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 org.springframework.data.relational.core.mapping.schemasqlgeneration;
+
+import org.springframework.data.relational.core.sql.SqlIdentifier;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * Class that models a Column for generating SQL for Schema generation.
+ *
+ * @author Kurt Niemi
+ */
+public class ColumnModel implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+ private final SqlIdentifier name;
+ private final String type;
+ private final boolean nullable;
+
+ public ColumnModel(SqlIdentifier name, String type, boolean nullable) {
+ this.name = name;
+ this.type = type;
+ this.nullable = nullable;
+ }
+
+ public ColumnModel(SqlIdentifier name, String type) {
+ this.name = name;
+ this.type = type;
+ this.nullable = false;
+ }
+
+ public SqlIdentifier getName() {
+ return name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public boolean isNullable() {
+ return nullable;
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/ForeignKeyColumnModel.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/ForeignKeyColumnModel.java
new file mode 100644
index 0000000000..04bc3d46f0
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/ForeignKeyColumnModel.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.springframework.data.relational.core.mapping.schemasqlgeneration;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * Class that models a Foreign Key relationship for generating SQL for Schema generation.
+ *
+ * @author Kurt Niemi
+ */
+public class ForeignKeyColumnModel implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+ private final TableModel foreignTable;
+ private final ColumnModel foreignColumn;
+ private final ColumnModel column;
+
+ public ForeignKeyColumnModel(TableModel foreignTable, ColumnModel foreignColumn, ColumnModel column) {
+ this.foreignTable = foreignTable;
+ this.foreignColumn = foreignColumn;
+ this.column = column;
+ }
+
+ public TableModel getForeignTable() {
+ return foreignTable;
+ }
+
+ public ColumnModel getForeignColumn() {
+ return foreignColumn;
+ }
+
+ public ColumnModel getColumn() {
+ return column;
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/SchemaSQLGenerationDataModel.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/SchemaSQLGenerationDataModel.java
new file mode 100644
index 0000000000..aa31a656f5
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/SchemaSQLGenerationDataModel.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.springframework.data.relational.core.mapping.schemasqlgeneration;
+
+import org.springframework.data.relational.core.mapping.BasicRelationalPersistentProperty;
+import org.springframework.data.relational.core.mapping.Column;
+import org.springframework.data.relational.core.mapping.RelationalMappingContext;
+import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Model class that contains Table/Column information that can be used
+ * to generate SQL for Schema generation.
+ *
+ * @author Kurt Niemi
+ */
+public class SchemaSQLGenerationDataModel implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+ private final List tableData = new ArrayList();
+ BaseTypeMapper typeMapper;
+
+ /**
+ * Default constructor so that we can deserialize a model
+ */
+ public SchemaSQLGenerationDataModel() {
+ }
+
+ /**
+ * Create model from a RelationalMappingContext
+ */
+ public SchemaSQLGenerationDataModel(RelationalMappingContext context) {
+
+ if (typeMapper == null) {
+ typeMapper = new BaseTypeMapper();
+ }
+
+ for (RelationalPersistentEntity entity : context.getPersistentEntities()) {
+ TableModel tableModel = new TableModel(entity.getTableName());
+
+ Iterator iter =
+ entity.getPersistentProperties(Column.class).iterator();
+
+ while (iter.hasNext()) {
+ BasicRelationalPersistentProperty p = iter.next();
+ ColumnModel columnModel = new ColumnModel(p.getColumnName(),
+ typeMapper.databaseTypeFromClass(p.getActualType()),
+ true);
+ tableModel.getColumns().add(columnModel);
+ }
+ tableData.add(tableModel);
+ }
+ }
+
+ public List getTableData() {
+ return tableData;
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/SchemaSQLGenerator.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/SchemaSQLGenerator.java
new file mode 100644
index 0000000000..8b9c8a77a0
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/SchemaSQLGenerator.java
@@ -0,0 +1,113 @@
+/*
+ * 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 org.springframework.data.relational.core.mapping.schemasqlgeneration;
+
+import org.springframework.data.relational.core.sql.IdentifierProcessing;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class SchemaSQLGenerator {
+
+ private final IdentifierProcessing identifierProcssing;
+ public SchemaSQLGenerator(IdentifierProcessing identifierProcessing) {
+ this.identifierProcssing = identifierProcessing;
+ }
+
+ List> reorderTablesInHierarchy(SchemaSQLGenerationDataModel dataModel) {
+
+ // ::TODO:: Take Parent/Child relationships into account (i.e if a child table has
+ // a Foreign Key to a table, that parent table needs to be created first.
+
+ // For now this method will simple put the tables in the same level
+ List> orderedTables = new ArrayList>();
+ List tables = new ArrayList();
+
+ for (TableModel table : dataModel.getTableData()) {
+ tables.add(table);
+ }
+ orderedTables.add(tables);
+
+ return orderedTables;
+ }
+
+ HashMap,String> mapClassToSQLType = null;
+
+ public String generateSQL(ColumnModel column) {
+
+ StringBuilder sql = new StringBuilder();
+ sql.append(column.getName().toSql(identifierProcssing));
+ sql.append(" ");
+
+ sql.append(column.getType());
+
+ if (!column.isNullable()) {
+ sql.append(" NOT NULL");
+ }
+
+ return sql.toString();
+ }
+
+ public String generatePrimaryKeySQL(TableModel table) {
+ // ::TODO:: Implement
+ return "";
+ }
+
+ public String generateForeignKeySQL(TableModel table) {
+ // ::TODO:: Implement
+ return "";
+ }
+
+ public String generateSQL(TableModel table) {
+
+ StringBuilder sql = new StringBuilder();
+
+ sql.append("CREATE TABLE ");
+ sql.append(table.getName().toSql(identifierProcssing));
+ sql.append(" (");
+
+ int numColumns = table.getColumns().size();
+ for (int i=0; i < numColumns; i++) {
+ sql.append(generateSQL(table.getColumns().get(i)));
+ if (i != numColumns-1) {
+ sql.append(",");
+ }
+ }
+
+ sql.append(generatePrimaryKeySQL(table));
+ sql.append(generateForeignKeySQL(table));
+
+ sql.append(" );");
+
+ return sql.toString();
+ }
+
+ public String generateSQL(SchemaSQLGenerationDataModel dataModel) {
+
+ StringBuilder sql = new StringBuilder();
+ List> orderedTables = reorderTablesInHierarchy(dataModel);
+
+ for (List tables : orderedTables) {
+ for (TableModel table : tables) {
+ String tableSQL = generateSQL(table);
+ sql.append(tableSQL + "\n");
+ }
+ }
+
+ return sql.toString();
+ }
+}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/TableModel.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/TableModel.java
new file mode 100644
index 0000000000..fb59264ffe
--- /dev/null
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/schemasqlgeneration/TableModel.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.springframework.data.relational.core.mapping.schemasqlgeneration;
+
+import org.springframework.data.relational.core.sql.SqlIdentifier;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class that models a Table for generating SQL for Schema generation.
+ *
+ * @author Kurt Niemi
+ */
+public class TableModel implements Serializable {
+ @Serial
+ private static final long serialVersionUID = 1L;
+ private final String schema;
+ private final SqlIdentifier name;
+ private final List columns = new ArrayList();
+ private final List keyColumns = new ArrayList();
+ private final List foreignKeyColumns = new ArrayList();
+
+ public TableModel(String schema, SqlIdentifier name) {
+ this.schema = schema;
+ this.name = name;
+ }
+ public TableModel(SqlIdentifier name) {
+ this(null, name);
+ }
+
+ public String getSchema() {
+ return schema;
+ }
+
+ public SqlIdentifier getName() {
+ return name;
+ }
+
+ public List getColumns() {
+ return columns;
+ }
+
+ public List getKeyColumns() {
+ return keyColumns;
+ }
+
+ public List getForeignKeyColumns() {
+ return foreignKeyColumns;
+ }
+}
diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/schemasqlgeneration/SchemaSQLGenerationDataModelTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/schemasqlgeneration/SchemaSQLGenerationDataModelTests.java
new file mode 100644
index 0000000000..517c369d63
--- /dev/null
+++ b/spring-data-relational/src/test/java/org/springframework/data/relational/schemasqlgeneration/SchemaSQLGenerationDataModelTests.java
@@ -0,0 +1,87 @@
+/*
+ * 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 org.springframework.data.relational.schemasqlgeneration;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.data.relational.core.mapping.Column;
+import org.springframework.data.relational.core.mapping.RelationalMappingContext;
+import org.springframework.data.relational.core.mapping.Table;
+import org.springframework.data.relational.core.mapping.schemasqlgeneration.SchemaSQLGenerationDataModel;
+import org.springframework.data.relational.core.mapping.schemasqlgeneration.SchemaSQLGenerator;
+import org.springframework.data.relational.core.mapping.schemasqlgeneration.TableModel;
+import org.springframework.data.relational.core.sql.IdentifierProcessing;
+import org.springframework.util.StringUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Unit tests for the {@link SchemaSQLGenerationDataModel}.
+ *
+ * @author Kurt Niemi
+ */
+public class SchemaSQLGenerationDataModelTests {
+
+ @Test
+ void testBasicSchemaSQLGeneration() {
+
+ IdentifierProcessing.Quoting quoting = new IdentifierProcessing.Quoting("`");
+ IdentifierProcessing identifierProcessing = IdentifierProcessing.create(quoting, IdentifierProcessing.LetterCasing.LOWER_CASE);
+ SchemaSQLGenerator generator = new SchemaSQLGenerator(identifierProcessing);
+
+ RelationalMappingContext context = new RelationalMappingContext();
+ context.getRequiredPersistentEntity(SchemaSQLGenerationDataModelTests.Luke.class);
+
+ SchemaSQLGenerationDataModel model = new SchemaSQLGenerationDataModel(context);
+ String sql = generator.generateSQL(model);
+ assertThat(sql).isEqualTo("CREATE TABLE `luke` (`force` VARCHAR(255),`be` VARCHAR(255),`with` VARCHAR(255),`you` VARCHAR(255) );\n");
+
+ context = new RelationalMappingContext();
+ context.getRequiredPersistentEntity(SchemaSQLGenerationDataModelTests.Vader.class);
+
+ model = new SchemaSQLGenerationDataModel(context);
+ sql = generator.generateSQL(model);
+ assertThat(sql).isEqualTo("CREATE TABLE `vader` (`luke_i_am_your_father` VARCHAR(255),`dark_side` TINYINT,`floater` FLOAT,`double_class` DOUBLE,`integer_class` INT );\n");
+ }
+
+
+ @Table
+ static class Luke {
+ @Column
+ public String force;
+ @Column
+ public String be;
+ @Column
+ public String with;
+ @Column
+ public String you;
+ }
+
+ @Table
+ static class Vader {
+ @Column
+ public String lukeIAmYourFather;
+ @Column
+ public Boolean darkSide;
+ @Column
+ public Float floater;
+ @Column
+ public Double doubleClass;
+ @Column
+ public Integer integerClass;
+ }
+
+
+}