From c677731f6a5ef47b89afe1d93351c30d109884a9 Mon Sep 17 00:00:00 2001 From: huanmeng_qwq <49704373+huanmeng-qwq@users.noreply.github.com> Date: Wed, 5 Apr 2023 00:46:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(migrate):=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=E8=A1=A8=E8=BF=81=E7=A7=BB=E7=9A=84=E6=93=8D=E4=BD=9C=20(#69)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DELETE语句缺少AND关键词连接 * feat(migrate): 添加对表迁移的操作 * Update SQLMigrate.java Co-authored-by: sonatype-lift[bot] <37194012+sonatype-lift[bot]@users.noreply.github.com> * feat(migrate): 添加对表迁移的操作 --------- Co-authored-by: sonatype-lift[bot] <37194012+sonatype-lift[bot]@users.noreply.github.com> --- .gitignore | 3 +- .../cc/carm/lib/easysql/api/SQLManager.java | 8 + .../lib/easysql/api/enums/MigrateResult.java | 58 +++++++ .../lib/easysql/api/migrate/SQLMigrate.java | 70 +++++++++ .../java/cc/carm/lib/easysql/EasySQLTest.java | 2 + .../lib/easysql/tests/TableMigrateTest.java | 70 +++++++++ .../lib/easysql/manager/SQLManagerImpl.java | 7 + .../migrate/AutoIncrementMigrateData.java | 13 ++ .../carm/lib/easysql/migrate/MigrateData.java | 33 ++++ .../lib/easysql/migrate/SQLMigrateImpl.java | 148 ++++++++++++++++++ 10 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 api/src/main/java/cc/carm/lib/easysql/api/enums/MigrateResult.java create mode 100644 api/src/main/java/cc/carm/lib/easysql/api/migrate/SQLMigrate.java create mode 100644 demo/src/test/java/cc/carm/lib/easysql/tests/TableMigrateTest.java create mode 100644 impl/src/main/java/cc/carm/lib/easysql/migrate/AutoIncrementMigrateData.java create mode 100644 impl/src/main/java/cc/carm/lib/easysql/migrate/MigrateData.java create mode 100644 impl/src/main/java/cc/carm/lib/easysql/migrate/SQLMigrateImpl.java diff --git a/.gitignore b/.gitignore index d7f0d54..9738b48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.idea/ **/target/ -**.iml \ No newline at end of file +**.iml +demo/logs \ No newline at end of file diff --git a/api/src/main/java/cc/carm/lib/easysql/api/SQLManager.java b/api/src/main/java/cc/carm/lib/easysql/api/SQLManager.java index 10661ee..437c42c 100644 --- a/api/src/main/java/cc/carm/lib/easysql/api/SQLManager.java +++ b/api/src/main/java/cc/carm/lib/easysql/api/SQLManager.java @@ -9,6 +9,7 @@ import cc.carm.lib.easysql.api.function.SQLBiFunction; import cc.carm.lib.easysql.api.function.SQLDebugHandler; import cc.carm.lib.easysql.api.function.SQLExceptionHandler; import cc.carm.lib.easysql.api.function.SQLFunction; +import cc.carm.lib.easysql.api.migrate.SQLMigrate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -265,6 +266,13 @@ public interface SQLManager { */ QueryBuilder createQuery(); + /** + * 新建一个迁移操作。 + * + * @return {@link SQLMigrate} + */ + SQLMigrate createMigrate(); + /** * 创建一条插入操作。 * diff --git a/api/src/main/java/cc/carm/lib/easysql/api/enums/MigrateResult.java b/api/src/main/java/cc/carm/lib/easysql/api/enums/MigrateResult.java new file mode 100644 index 0000000..677bdaf --- /dev/null +++ b/api/src/main/java/cc/carm/lib/easysql/api/enums/MigrateResult.java @@ -0,0 +1,58 @@ +package cc.carm.lib.easysql.api.enums; + +/** + * 2022/11/28
+ * EasySQL
+ * + * @author huanmeng_qwq + */ +public class MigrateResult { + /** + * 旧表不存在 + */ + public static final MigrateResult OLD_TABLE_NOT_EXIST = new MigrateResult(true); + + /** + * 新表已存在 + */ + public static final MigrateResult NEW_TABLE_EXIST = new MigrateResult(false); + + /** + * 新表字段为空 + */ + public static final MigrateResult NEW_COLUMN_EMPTY = new MigrateResult(false); + + /** + * 旧表字段为在新表这设置对应的字段名 + */ + public static final MigrateResult COLUMN_NOT_SET = new MigrateResult(false); + + /** + * 迁移成功 + */ + public static final MigrateResult SUCCESS = new MigrateResult(true); + + private final boolean success; + private Throwable error; + + MigrateResult(boolean success) { + this.success = success; + } + + public MigrateResult(boolean success, Throwable error) { + this.success = success; + this.error = error; + } + + public static MigrateResult from(MigrateResult migrateResult, Throwable error) { + return new MigrateResult(migrateResult.success, error); + } + + public boolean success() { + return success; + } + + public Throwable error() { + return error; + } +} diff --git a/api/src/main/java/cc/carm/lib/easysql/api/migrate/SQLMigrate.java b/api/src/main/java/cc/carm/lib/easysql/api/migrate/SQLMigrate.java new file mode 100644 index 0000000..57743f9 --- /dev/null +++ b/api/src/main/java/cc/carm/lib/easysql/api/migrate/SQLMigrate.java @@ -0,0 +1,70 @@ +package cc.carm.lib.easysql.api.migrate; + +import cc.carm.lib.easysql.api.enums.IndexType; +import cc.carm.lib.easysql.api.enums.MigrateResult; +import org.jetbrains.annotations.Contract; + +import java.sql.SQLException; + +/** + * 将现有的表结构与数据迁移之新的表中 + * + * @author huanmeng_qwq + * @since 0.4.7 + */ +public interface SQLMigrate { + + /** + * 为迁移工作定义前后的表名信息 + * + * @param oldTableName 旧表名 + * @param newTableName 新表名 + * @param newTableSettings 新表的设置 + * @return {@link SQLMigrate} + */ + @Contract("null,_,_ -> fail;!null,_,_ -> this") + SQLMigrate tableName(String oldTableName, String newTableName, String newTableSettings); + + /** + * 为迁移工作定义前后的列名信息 + * + * @param oldColumnName 旧列名 + * @param newColumnName 新列名 + * @param newColumnSettings 新列的设置 + * @return {@link SQLMigrate} + */ + @Contract("null,_,_ -> fail;!null,_,_ -> this") + default SQLMigrate column(String oldColumnName, String newColumnName, String newColumnSettings) { + return column(oldColumnName, newColumnName, newColumnSettings, null); + } + + /** + * 为迁移工作定义前后的列名信息 + * + * @param oldColumnName 旧列名 + * @param newColumnName 新列名 + * @param newColumnSettings 新列的设置 + * @param indexType 索引类型 + * @return {@link SQLMigrate} + */ + @Contract("null,_,_,_ -> fail;!null,_,_,_ -> this") + SQLMigrate column(String oldColumnName, String newColumnName, String newColumnSettings, IndexType indexType); + + /** + * 为迁移工作定义前后的自增列名信息 + * + * @param oldColumnName 旧列名 + * @param newColumnName 新列名 + * @return {@link SQLMigrate} + */ + @Contract("null,_->fail;!null,_ -> this") + SQLMigrate autoIncrementColumn(String oldColumnName, String newColumnName); + + /** + * 迁移数据 + * + * @return {@link MigrateResult} + */ + MigrateResult migrate() throws SQLException; + +} diff --git a/demo/src/test/java/cc/carm/lib/easysql/EasySQLTest.java b/demo/src/test/java/cc/carm/lib/easysql/EasySQLTest.java index 3925749..4d92537 100644 --- a/demo/src/test/java/cc/carm/lib/easysql/EasySQLTest.java +++ b/demo/src/test/java/cc/carm/lib/easysql/EasySQLTest.java @@ -56,6 +56,8 @@ public class EasySQLTest { tests.add(new TableMetadataTest()); // tests.add(new DeleteTest()); + tests.add(new TableMigrateTest()); + print("准备进行测试..."); int index = 1; diff --git a/demo/src/test/java/cc/carm/lib/easysql/tests/TableMigrateTest.java b/demo/src/test/java/cc/carm/lib/easysql/tests/TableMigrateTest.java new file mode 100644 index 0000000..4abb718 --- /dev/null +++ b/demo/src/test/java/cc/carm/lib/easysql/tests/TableMigrateTest.java @@ -0,0 +1,70 @@ +package cc.carm.lib.easysql.tests; + +import cc.carm.lib.easysql.TestHandler; +import cc.carm.lib.easysql.api.SQLManager; +import cc.carm.lib.easysql.api.SQLQuery; +import cc.carm.lib.easysql.api.enums.IndexType; +import cc.carm.lib.easysql.api.enums.MigrateResult; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 2022/11/28
+ * EasySQL
+ * + * @author huanmeng_qwq + */ +public class TableMigrateTest extends TestHandler { + @Override + public void onTest(SQLManager sqlManager) throws Exception { + print(" 创建 test_migrate_table"); + sqlManager.createTable("test_migrate_table") + .addAutoIncrementColumn("id") + .addColumn("uuid", "VARCHAR(36) NOT NULL", "用户UUID") + .addColumn("username", "VARCHAR(16) NOT NULL", "用户名") + .addColumn("age", "TINYINT DEFAULT 0 NOT NULL", "年龄") + + .setIndex("uuid", IndexType.UNIQUE_KEY) + .build().execute(); + + print(" 向 test_migrate_table 写入数据"); + sqlManager.createInsert("test_migrate_table") + .setColumnNames("uuid", "username", "age") + .setParams("1234567890", "qwq", 18) + .execute(); + + print(" 迁移 test_migrate_table 至 test_transfer_table"); + MigrateResult migrate = sqlManager.createMigrate() + .tableName("test_migrate_table", "test_transfer_table", null) + .autoIncrementColumn("id", "dbId") + .column("uuid", "uniqueId", "VARCHAR(40) NOT NULL") + .column("username", "name", "VARCHAR(20) NOT NULL") + .column("age", "age", "TINYINT DEFAULT 0 NOT NULL") + .migrate(); + + if (migrate.error() != null) { + migrate.error().printStackTrace(); + } + + Set set = sqlManager.fetchTableMetadata("test_transfer_table").listColumns().join() + .stream() + .map(String::toLowerCase) + .collect(Collectors.toSet()); + print(" 迁移后的表结构: " + set); + boolean containsAll = set.containsAll(Stream.of + ("dbId", "uniqueId", "name", "age").map(String::toLowerCase).collect(Collectors.toSet())); + print(" 迁移结果: " + (migrate.success() ? "true" : migrate.error()) + " , 是否包含所有字段: " + containsAll); + try (SQLQuery query = sqlManager.createQuery().inTable("test_transfer_table").build().execute()) { + while (query.getResultSet().next()) { + print(" 迁移后的数据: " + + query.getResultSet().getInt("dbId") + " , " + + query.getResultSet().getString("uniqueId") + " , " + + query.getResultSet().getString("name") + " , " + + query.getResultSet().getInt("age") + ); + } + } + } +} diff --git a/impl/src/main/java/cc/carm/lib/easysql/manager/SQLManagerImpl.java b/impl/src/main/java/cc/carm/lib/easysql/manager/SQLManagerImpl.java index 4178b42..92a2f9e 100644 --- a/impl/src/main/java/cc/carm/lib/easysql/manager/SQLManagerImpl.java +++ b/impl/src/main/java/cc/carm/lib/easysql/manager/SQLManagerImpl.java @@ -14,7 +14,9 @@ import cc.carm.lib.easysql.api.function.SQLBiFunction; import cc.carm.lib.easysql.api.function.SQLDebugHandler; import cc.carm.lib.easysql.api.function.SQLExceptionHandler; import cc.carm.lib.easysql.api.function.SQLFunction; +import cc.carm.lib.easysql.api.migrate.SQLMigrate; import cc.carm.lib.easysql.builder.impl.*; +import cc.carm.lib.easysql.migrate.SQLMigrateImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -199,6 +201,11 @@ public class SQLManagerImpl implements SQLManager { return new QueryBuilderImpl(this); } + @Override + public SQLMigrate createMigrate() { + return new SQLMigrateImpl(this); + } + @Override public InsertBuilder> createInsertBatch(@NotNull String tableName) { return new InsertBuilderImpl>(this, tableName) { diff --git a/impl/src/main/java/cc/carm/lib/easysql/migrate/AutoIncrementMigrateData.java b/impl/src/main/java/cc/carm/lib/easysql/migrate/AutoIncrementMigrateData.java new file mode 100644 index 0000000..d407288 --- /dev/null +++ b/impl/src/main/java/cc/carm/lib/easysql/migrate/AutoIncrementMigrateData.java @@ -0,0 +1,13 @@ +package cc.carm.lib.easysql.migrate; + +/** + * 2022/11/28
+ * EasySQL
+ * + * @author huanmeng_qwq + */ +public class AutoIncrementMigrateData extends MigrateData { + public AutoIncrementMigrateData(String name) { + super(name, null, null); + } +} diff --git a/impl/src/main/java/cc/carm/lib/easysql/migrate/MigrateData.java b/impl/src/main/java/cc/carm/lib/easysql/migrate/MigrateData.java new file mode 100644 index 0000000..de6a27e --- /dev/null +++ b/impl/src/main/java/cc/carm/lib/easysql/migrate/MigrateData.java @@ -0,0 +1,33 @@ +package cc.carm.lib.easysql.migrate; + +import cc.carm.lib.easysql.api.enums.IndexType; + +/** + * 2022/11/28
+ * EasySQL
+ * + * @author huanmeng_qwq + */ +public class MigrateData { + private final String name; + private final String settings; + private final IndexType indexType; + + public MigrateData(String name, String settings, IndexType indexType) { + this.name = name; + this.settings = settings; + this.indexType = indexType; + } + + public String name() { + return name; + } + + public String settings() { + return settings; + } + + public IndexType indexType() { + return indexType; + } +} diff --git a/impl/src/main/java/cc/carm/lib/easysql/migrate/SQLMigrateImpl.java b/impl/src/main/java/cc/carm/lib/easysql/migrate/SQLMigrateImpl.java new file mode 100644 index 0000000..8e20319 --- /dev/null +++ b/impl/src/main/java/cc/carm/lib/easysql/migrate/SQLMigrateImpl.java @@ -0,0 +1,148 @@ +package cc.carm.lib.easysql.migrate; + +import cc.carm.lib.easysql.api.SQLManager; +import cc.carm.lib.easysql.api.SQLQuery; +import cc.carm.lib.easysql.api.action.PreparedSQLUpdateAction; +import cc.carm.lib.easysql.api.builder.TableCreateBuilder; +import cc.carm.lib.easysql.api.enums.IndexType; +import cc.carm.lib.easysql.api.enums.MigrateResult; +import cc.carm.lib.easysql.api.migrate.SQLMigrate; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 2022/11/28
+ * EasySQL
+ * + * @author huanmeng_qwq + */ +public class SQLMigrateImpl implements SQLMigrate { + private final SQLManager sqlManager; + + private final Map columnMap; + + private String oldTableName; + private MigrateData newTableData; + + public SQLMigrateImpl(SQLManager sqlManager) { + this.sqlManager = sqlManager; + this.columnMap = new LinkedHashMap<>(); + } + + @Override + public SQLMigrate tableName(String oldTableName, String newTableName, String newTableSettings) { + if (oldTableName == null) { + throw new IllegalArgumentException("oldTableName can not be null"); + } + this.oldTableName = oldTableName; + this.newTableData = new MigrateData(newTableName, newTableSettings, null); + return this; + } + + @Override + public SQLMigrate column(String oldColumnName, String newColumnName, String newColumnSettings, IndexType indexType) { + if (oldColumnName == null) { + throw new IllegalArgumentException("oldColumnName can not be null"); + } + columnMap.put(oldColumnName, new MigrateData(newColumnName, newColumnSettings, indexType)); + return this; + } + + @Override + public SQLMigrate autoIncrementColumn(String oldColumnName, String newColumnName) { + if (oldColumnName == null) { + throw new IllegalArgumentException("oldColumnName can not be null"); + } + columnMap.put(oldColumnName, new AutoIncrementMigrateData(newColumnName)); + return this; + } + + @Override + public MigrateResult migrate() throws SQLException { + if (oldTableName == null) { + return MigrateResult.from(MigrateResult.OLD_TABLE_NOT_EXIST, new IllegalArgumentException("oldTableName can not be null")); + } + if (newTableData == null) { + return MigrateResult.from(MigrateResult.NEW_TABLE_EXIST, new IllegalArgumentException("new table name can not be null")); + } + if (columnMap.isEmpty()) { + return MigrateResult.from(MigrateResult.NEW_COLUMN_EMPTY, new IllegalArgumentException("new column can not be empty")); + } + try { + // check table + Set columns = sqlManager.fetchTableMetadata(oldTableName).listColumns().join(); + for (String column : columns) { + if (columnMap.keySet().stream().noneMatch(k -> k.toLowerCase(Locale.ROOT).equals(column.toLowerCase(Locale.ROOT)))) { + return MigrateResult.from(MigrateResult.COLUMN_NOT_SET, new IllegalArgumentException("column " + column + " not set")); + } + } + // create new table + TableCreateBuilder table = sqlManager.createTable(newTableData.name()); + if (newTableData.settings() != null) { + table.setTableSettings(newTableData.settings()); + } + // add columns + for (Map.Entry entry : columnMap.entrySet()) { + MigrateData migrateData = entry.getValue(); + if (migrateData.name() == null) { + // ignore + continue; + } + if (migrateData instanceof AutoIncrementMigrateData) { + table.addAutoIncrementColumn(migrateData.name()); + continue; + } + table.addColumn(migrateData.name(), migrateData.settings()); + if (migrateData.indexType() != null) { + table.setIndex(migrateData.name(), migrateData.indexType()); + } + } + table.build().execute(); + + // insert data + try (SQLQuery query = sqlManager.createQuery().inTable(oldTableName).build().execute()) { + insert(query.getResultSet()); + } + } catch (SQLException e) { + return new MigrateResult(false, e); + } + return MigrateResult.SUCCESS; + } + + private void insert(ResultSet resultSet) throws SQLException { + while (resultSet.next()) { + Map columnNames = tableColumnNames(); + PreparedSQLUpdateAction updateAction = sqlManager.createInsert(newTableData.name()).setColumnNames(columnNames.values().toArray(new String[0])); + Object[] values = new Object[columnNames.size()]; + int i = 0; + for (Map.Entry entry : columnNames.entrySet()) { + values[i] = resultSet.getObject(entry.getKey()); + ++i; + } + updateAction.setParams(values); + updateAction.execute(); + } + } + + private Map tableColumnNames() { + Map map = new ConcurrentHashMap<>(); + for (Map.Entry entry : columnMap.entrySet()) { + MigrateData migrateData = entry.getValue(); + if (migrateData.name() == null) { + // ignore + continue; + } + if (migrateData instanceof AutoIncrementMigrateData) { + continue; + } + map.put(entry.getKey(), migrateData.name()); + } + return map; + } +}