From 5720979ddfa8d2999f4e26352e14178787e0dc78 Mon Sep 17 00:00:00 2001 From: ajdin Date: Tue, 7 May 2024 17:55:59 +0200 Subject: [PATCH 1/3] added: initial groundwork for extension support (target 3.0) --- .../rosetta/common/models/Column.java | 10 ++ .../rosetta/common/models/Extension.java | 36 +++++ .../rosetta/common/models/Table.java | 16 +- .../models/enums/ExtensionTypesEnum.java | 5 + .../models/enums/OperationTypeEnum.java | 10 ++ .../common/types/RosettaModuleTypes.java | 2 + .../rosetta/ddl/DDLExtensionColumn.java | 18 +++ .../rosetta/ddl/DDLExtensionTable.java | 19 +++ .../change/ChangeHandlerImplementation.java | 142 +++++++++++++++++- .../column/DDLColumnChangeTest.java | 42 ++++++ .../extensions/table/DDLTableChangeTest.java | 43 ++++++ 11 files changed, 333 insertions(+), 10 deletions(-) create mode 100644 common/src/main/java/com/adaptivescale/rosetta/common/models/Extension.java create mode 100644 common/src/main/java/com/adaptivescale/rosetta/common/models/enums/ExtensionTypesEnum.java create mode 100644 common/src/main/java/com/adaptivescale/rosetta/common/models/enums/OperationTypeEnum.java create mode 100644 ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java create mode 100644 ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionTable.java create mode 100644 ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java create mode 100644 ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java diff --git a/common/src/main/java/com/adaptivescale/rosetta/common/models/Column.java b/common/src/main/java/com/adaptivescale/rosetta/common/models/Column.java index f77d9f4b..2d3d2f70 100644 --- a/common/src/main/java/com/adaptivescale/rosetta/common/models/Column.java +++ b/common/src/main/java/com/adaptivescale/rosetta/common/models/Column.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; public class Column { @@ -24,6 +25,7 @@ public class Column { private List columnProperties = new ArrayList<>(); private Tests tests; private List foreignKeys; + private Set extensions; public Column() { } @@ -162,4 +164,12 @@ public Tests getTests() { public void setTests(Tests tests) { this.tests = tests; } + + public Set getExtensions() { + return extensions; + } + + public void setExtensions(Set extensions) { + this.extensions = extensions; + } } diff --git a/common/src/main/java/com/adaptivescale/rosetta/common/models/Extension.java b/common/src/main/java/com/adaptivescale/rosetta/common/models/Extension.java new file mode 100644 index 00000000..8dbacb7b --- /dev/null +++ b/common/src/main/java/com/adaptivescale/rosetta/common/models/Extension.java @@ -0,0 +1,36 @@ +package com.adaptivescale.rosetta.common.models; + + +import com.adaptivescale.rosetta.common.models.enums.ExtensionTypesEnum; + +import java.util.Map; + +public class Extension { + private String name; + private ExtensionTypesEnum type; + private Map actions; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ExtensionTypesEnum getType() { + return type; + } + + public void setType(ExtensionTypesEnum type) { + this.type = type; + } + + public Map getActions() { + return actions; + } + + public void setActions(Map actions) { + this.actions = actions; + } +} diff --git a/common/src/main/java/com/adaptivescale/rosetta/common/models/Table.java b/common/src/main/java/com/adaptivescale/rosetta/common/models/Table.java index 2969088f..e07f35b7 100644 --- a/common/src/main/java/com/adaptivescale/rosetta/common/models/Table.java +++ b/common/src/main/java/com/adaptivescale/rosetta/common/models/Table.java @@ -1,8 +1,6 @@ package com.adaptivescale.rosetta.common.models; -import java.util.Collection; -import java.util.List; -import java.util.Objects; +import java.util.*; public class Table { @@ -17,6 +15,8 @@ public class Table { private Collection columns; + private Set extensions; + public String getName() { return name; } @@ -74,7 +74,15 @@ public void setIndices(List indices) { this.indices = indices; } - @Override + public Set getExtensions() { + return extensions; + } + + public void setExtensions(Set extensions) { + this.extensions = extensions; + } + + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; diff --git a/common/src/main/java/com/adaptivescale/rosetta/common/models/enums/ExtensionTypesEnum.java b/common/src/main/java/com/adaptivescale/rosetta/common/models/enums/ExtensionTypesEnum.java new file mode 100644 index 00000000..bc880453 --- /dev/null +++ b/common/src/main/java/com/adaptivescale/rosetta/common/models/enums/ExtensionTypesEnum.java @@ -0,0 +1,5 @@ +package com.adaptivescale.rosetta.common.models.enums; + +public enum ExtensionTypesEnum { + DDL_EXTENSION, +} diff --git a/common/src/main/java/com/adaptivescale/rosetta/common/models/enums/OperationTypeEnum.java b/common/src/main/java/com/adaptivescale/rosetta/common/models/enums/OperationTypeEnum.java new file mode 100644 index 00000000..9ae66406 --- /dev/null +++ b/common/src/main/java/com/adaptivescale/rosetta/common/models/enums/OperationTypeEnum.java @@ -0,0 +1,10 @@ +package com.adaptivescale.rosetta.common.models.enums; + +public enum OperationTypeEnum { + PRE_CREATE, + PRE_ALTER, + PRE_DROP, + POST_CREATE, + POST_ALTER, + POST_DROP +} diff --git a/common/src/main/java/com/adaptivescale/rosetta/common/types/RosettaModuleTypes.java b/common/src/main/java/com/adaptivescale/rosetta/common/types/RosettaModuleTypes.java index 48489e53..b6dae4e6 100644 --- a/common/src/main/java/com/adaptivescale/rosetta/common/types/RosettaModuleTypes.java +++ b/common/src/main/java/com/adaptivescale/rosetta/common/types/RosettaModuleTypes.java @@ -25,4 +25,6 @@ public enum RosettaModuleTypes { TABLE_EXTRACTOR, VIEW_EXTRACTOR, DIFF_TESTER, + DDL_EXTENSION_TABLE, + DDL_EXTENSION_COLUMN, } diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java new file mode 100644 index 00000000..5d1afa26 --- /dev/null +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java @@ -0,0 +1,18 @@ +package com.adaptivescale.rosetta.ddl; + +import com.adaptivescale.rosetta.common.models.Column; +import com.adaptivescale.rosetta.common.models.Table; + + +public interface DDLExtensionColumn { + + String preCreateColumn(Column table, Object action); + String postCreateColumn(Column table, Object action); + + String preDropColumn(Column table, Object action); + String postDropColumn(Column table, Object action); + + String preAlterColumn(Column table, Object action); + String postAlterColumn(Column table, Object action); + +} diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionTable.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionTable.java new file mode 100644 index 00000000..8d0cd600 --- /dev/null +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionTable.java @@ -0,0 +1,19 @@ +package com.adaptivescale.rosetta.ddl; + +import com.adaptivescale.rosetta.common.models.*; +import com.adaptivescale.rosetta.ddl.change.model.ColumnChange; +import com.adaptivescale.rosetta.ddl.change.model.ForeignKeyChange; + + +public interface DDLExtensionTable { + + String preCreateTable(Table table, Object action); + String postCreateTable(Table table, Object action); + + String preDropTable(Table actual, Object action); + String postDropTable(Table actual, Object action); + + String preAlterTable(Table expected, Object action); + String postAlterTable(Table expected, Object action); + +} diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java index 70145717..1f912928 100644 --- a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java @@ -1,12 +1,23 @@ package com.adaptivescale.rosetta.ddl.change; +import com.adaptivescale.rosetta.common.helpers.ModuleLoader; +import com.adaptivescale.rosetta.common.models.Column; +import com.adaptivescale.rosetta.common.models.Table; +import com.adaptivescale.rosetta.common.models.enums.OperationTypeEnum; +import com.adaptivescale.rosetta.common.types.RosettaModuleTypes; import com.adaptivescale.rosetta.ddl.DDL; +import com.adaptivescale.rosetta.ddl.DDLExtensionColumn; +import com.adaptivescale.rosetta.ddl.DDLExtensionTable; import com.adaptivescale.rosetta.ddl.change.model.*; import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Optional; + +import static com.adaptivescale.rosetta.common.models.enums.OperationTypeEnum.*; @Slf4j public class ChangeHandlerImplementation implements ChangeHandler { @@ -35,7 +46,10 @@ public String createDDLForChanges(List> changes) { ddlStatements.add(onTableSchemaChange((TableSchemaChange) change)); break; case TABLE: + + // TODOD preTableScript ddlStatements.add(onTableChange((TableChange) change)); + // tODo postTableScript break; case COLUMN: ddlStatements.add(onColumnChange((ColumnChange) change)); @@ -69,11 +83,35 @@ public String onDatabaseChange(DatabaseChange databaseChange) { public String onTableChange(TableChange change) { switch (change.getStatus()) { case DROP: - return ddl.dropTable(change.getActual()); + StringBuilder dropQueryBuilder = new StringBuilder(); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + dropQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_DROP, "PRE_DROP")); + } + dropQueryBuilder.append(ddl.dropTable(change.getActual())); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + dropQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_DROP, "POST_DROP")); + } + return dropQueryBuilder.toString(); case ADD: - return ddl.createTable(change.getExpected(), false); + StringBuilder addQueryBuilder = new StringBuilder(); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + addQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_CREATE, "PRE_CREATE")); + } + addQueryBuilder.append(ddl.createTable(change.getExpected(), false)); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + addQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_CREATE, "POST_CREATE")); + } + return addQueryBuilder.toString(); case ALTER: - return ddl.alterTable(change.getExpected(), change.getActual()); + StringBuilder alterQueryBuilder = new StringBuilder(); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + alterQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_ALTER, "PRE_ALTER")); + } + alterQueryBuilder.append(ddl.alterTable(change.getExpected(), change.getActual())); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + alterQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_ALTER, "POST_ALTER")); + } + return alterQueryBuilder.toString(); default: throw new RuntimeException("Operation " + change.getStatus() + " for table not supported"); } @@ -93,16 +131,108 @@ public String onTableSchemaChange(TableSchemaChange change) { public String onColumnChange(ColumnChange change) { switch (change.getStatus()) { case ALTER: - return ddl.alterColumn(change); + StringBuilder alterQueryBuilder = new StringBuilder(); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + alterQueryBuilder.append(executeColumnExtensions(change.getExpected(), PRE_ALTER, "PRE_ALTER")); + } + alterQueryBuilder.append(ddl.alterColumn(change)); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + alterQueryBuilder.append(executeColumnExtensions(change.getExpected(), POST_ALTER, "POST_ALTER")); + } + return alterQueryBuilder.toString(); case DROP: - return ddl.dropColumn(change); + StringBuilder dropQueryBuilder = new StringBuilder(); + if (change.getActual()!=null && change.getActual().getExtensions() != null) { + dropQueryBuilder.append(executeColumnExtensions(change.getActual(), PRE_DROP, "PRE_DROP")); + } + dropQueryBuilder.append(ddl.dropColumn(change)); + if (change.getActual()!=null && change.getActual().getExtensions() != null) { + dropQueryBuilder.append(executeColumnExtensions(change.getActual(), POST_DROP, "POST_DROP")); + } + return dropQueryBuilder.toString(); case ADD: - return ddl.addColumn(change); + StringBuilder addQueryBuilder = new StringBuilder(); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + addQueryBuilder.append(executeColumnExtensions(change.getExpected(), PRE_CREATE, "PRE_CREATE")); + } + addQueryBuilder.append(ddl.addColumn(change)); + if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { + addQueryBuilder.append(executeColumnExtensions(change.getExpected(), POST_CREATE, "POST_CREATE")); + } + return addQueryBuilder.toString(); default: throw new RuntimeException("Operation " + change.getStatus() + " for column not supported"); } } + public String executeTableExtensions(Table table, OperationTypeEnum status, Object action) { + Optional> tableExtension = ModuleLoader.loadModuleByAnnotationClassValues("com.adaptivescale.rosetta.ddl.extensions.table", RosettaModuleTypes.DDL_EXTENSION_TABLE, "SQL"); + DDLExtensionTable ddlExtensionTable = null; + if (tableExtension.isPresent()) { + try { + ddlExtensionTable = (DDLExtensionTable) tableExtension.get().getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | + NoSuchMethodException e) { + log.warn("Failed to load table ddl extension %s - skipping", tableExtension.get().getName()); + } + } else { + log.warn("No table ddl extension found - skipping", tableExtension.get().getName()); + } + if (ddlExtensionTable == null) { + return ""; + } + switch (status) { + case PRE_CREATE: + return ddlExtensionTable.preCreateTable(table, action); + case PRE_ALTER: + return ddlExtensionTable.preAlterTable(table, action); + case PRE_DROP: + return ddlExtensionTable.preDropTable(table, action); + case POST_CREATE: + return ddlExtensionTable.postCreateTable(table, action); + case POST_ALTER: + return ddlExtensionTable.postAlterTable(table, action); + case POST_DROP: + return ddlExtensionTable.postDropTable(table, action); + default: + return ""; + } + } + + public String executeColumnExtensions(Column column, OperationTypeEnum status, Object action) { + Optional> columnExtension = ModuleLoader.loadModuleByAnnotationClassValues("com.adaptivescale.rosetta.ddl.extensions.column", RosettaModuleTypes.DDL_EXTENSION_COLUMN, "SQL"); + DDLExtensionColumn ddlExtensionColumn = null; + if (columnExtension.isPresent()) { + try { + ddlExtensionColumn = (DDLExtensionColumn) columnExtension.get().getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | + NoSuchMethodException e) { + log.warn("Failed to load column ddl extension %s - skipping", columnExtension.get().getName()); + } + } else { + log.warn("No column ddl extension found - skipping", columnExtension.get().getName()); + } + if (ddlExtensionColumn == null) { + return ""; + } + switch (status) { + case PRE_CREATE: + return ddlExtensionColumn.preCreateColumn(column, action); + case PRE_ALTER: + return ddlExtensionColumn.preAlterColumn(column, action); + case PRE_DROP: + return ddlExtensionColumn.preDropColumn(column, action); + case POST_CREATE: + return ddlExtensionColumn.postCreateColumn(column, action); + case POST_ALTER: + return ddlExtensionColumn.postAlterColumn(column, action); + case POST_DROP: + return ddlExtensionColumn.postDropColumn(column, action); + default: + return ""; + } + } + @Override public String onForeignKeyChange(ForeignKeyChange change) { switch (change.getStatus()) { diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java new file mode 100644 index 00000000..f5421b6d --- /dev/null +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java @@ -0,0 +1,42 @@ +package com.adaptivescale.rosetta.ddl.extensions.column; + +import com.adaptivescale.rosetta.common.annotations.RosettaModule; +import com.adaptivescale.rosetta.common.models.Column; +import com.adaptivescale.rosetta.common.types.RosettaModuleTypes; +import com.adaptivescale.rosetta.ddl.DDLExtensionColumn; + +@RosettaModule( + name = "SQL", + type = RosettaModuleTypes.DDL_EXTENSION_COLUMN +) +public class DDLColumnChangeTest implements DDLExtensionColumn { + @Override + public String preCreateColumn(Column table, Object action) { + return action.toString(); + } + + @Override + public String postCreateColumn(Column table, Object action) { + return action.toString(); + } + + @Override + public String preDropColumn(Column table, Object action) { + return action.toString(); + } + + @Override + public String postDropColumn(Column table, Object action) { + return action.toString(); + } + + @Override + public String preAlterColumn(Column table, Object action) { + return action.toString(); + } + + @Override + public String postAlterColumn(Column table, Object action) { + return action.toString(); + } +} diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java new file mode 100644 index 00000000..db89ed31 --- /dev/null +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java @@ -0,0 +1,43 @@ +package com.adaptivescale.rosetta.ddl.extensions.table; + +import com.adaptivescale.rosetta.common.annotations.RosettaModule; +import com.adaptivescale.rosetta.common.models.Table; +import com.adaptivescale.rosetta.common.types.RosettaModuleTypes; +import com.adaptivescale.rosetta.ddl.DDLExtensionTable; + +@RosettaModule( + name = "SQL", + type = RosettaModuleTypes.DDL_EXTENSION_COLUMN +) +public class DDLTableChangeTest implements DDLExtensionTable { + + @Override + public String preCreateTable(Table table, Object action) { + return "preCreateTable"; + } + + @Override + public String postCreateTable(Table table, Object action) { + return "postCreateTable"; + } + + @Override + public String preDropTable(Table actual, Object action) { + return "preDropTable"; + } + + @Override + public String postDropTable(Table actual, Object action) { + return "postDropTable"; + } + + @Override + public String preAlterTable(Table expected, Object action) { + return "preAlterTable"; + } + + @Override + public String postAlterTable(Table expected, Object action) { + return "postAlterTable"; + } +} From 0a69e6b7ee08e39f9e27e6fbd7ed49b0f1bba5f7 Mon Sep 17 00:00:00 2001 From: Femi3211 Date: Mon, 20 May 2024 14:25:15 +0200 Subject: [PATCH 2/3] modified: extension for SQL migration level for rosetta, pointing to 3.0.0 alpha --- .../rosetta/ddl/DDLExtensionColumn.java | 13 +- .../change/ChangeHandlerImplementation.java | 118 +++++++++++------- .../column/DDLColumnChangeTest.java | 12 +- .../extensions/table/DDLTableChangeTest.java | 14 +-- 4 files changed, 92 insertions(+), 65 deletions(-) diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java index 5d1afa26..249c7103 100644 --- a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/DDLExtensionColumn.java @@ -1,18 +1,17 @@ package com.adaptivescale.rosetta.ddl; import com.adaptivescale.rosetta.common.models.Column; -import com.adaptivescale.rosetta.common.models.Table; public interface DDLExtensionColumn { - String preCreateColumn(Column table, Object action); - String postCreateColumn(Column table, Object action); + String preCreateColumn(Column column, Object action); + String postCreateColumn(Column column, Object action); - String preDropColumn(Column table, Object action); - String postDropColumn(Column table, Object action); + String preDropColumn(Column column, Object action); + String postDropColumn(Column column, Object action); - String preAlterColumn(Column table, Object action); - String postAlterColumn(Column table, Object action); + String preAlterColumn(Column column, Object action); + String postAlterColumn(Column column, Object action); } diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java index 1f912928..81a39ce5 100644 --- a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/change/ChangeHandlerImplementation.java @@ -2,6 +2,7 @@ import com.adaptivescale.rosetta.common.helpers.ModuleLoader; import com.adaptivescale.rosetta.common.models.Column; +import com.adaptivescale.rosetta.common.models.Extension; import com.adaptivescale.rosetta.common.models.Table; import com.adaptivescale.rosetta.common.models.enums.OperationTypeEnum; import com.adaptivescale.rosetta.common.types.RosettaModuleTypes; @@ -12,10 +13,7 @@ import lombok.extern.slf4j.Slf4j; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Optional; +import java.util.*; import static com.adaptivescale.rosetta.common.models.enums.OperationTypeEnum.*; @@ -32,7 +30,7 @@ public ChangeHandlerImplementation(DDL ddl, Comparator> changeComparat @Override public String createDDLForChanges(List> changes) { - if(changeComparator != null){ + if (changeComparator != null) { changes.sort(changeComparator); } @@ -46,10 +44,7 @@ public String createDDLForChanges(List> changes) { ddlStatements.add(onTableSchemaChange((TableSchemaChange) change)); break; case TABLE: - - // TODOD preTableScript ddlStatements.add(onTableChange((TableChange) change)); - // tODo postTableScript break; case COLUMN: ddlStatements.add(onColumnChange((ColumnChange) change)); @@ -83,35 +78,53 @@ public String onDatabaseChange(DatabaseChange databaseChange) { public String onTableChange(TableChange change) { switch (change.getStatus()) { case DROP: - StringBuilder dropQueryBuilder = new StringBuilder(); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - dropQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_DROP, "PRE_DROP")); - } - dropQueryBuilder.append(ddl.dropTable(change.getActual())); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - dropQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_DROP, "POST_DROP")); - } - return dropQueryBuilder.toString(); + StringBuilder dropQueryBuilder = new StringBuilder(); + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(PRE_DROP.name())).findFirst(); + first.ifPresent(extension -> dropQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_DROP, extension.getActions().get(PRE_DROP.name())))); + } + + dropQueryBuilder.append(ddl.dropTable(change.getActual())); + + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(POST_DROP.name())).findFirst(); + first.ifPresent(extension -> dropQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_DROP, extension.getActions().get(POST_DROP.name())))); + } + return dropQueryBuilder.toString(); case ADD: StringBuilder addQueryBuilder = new StringBuilder(); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - addQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_CREATE, "PRE_CREATE")); + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(PRE_CREATE.name())).findFirst(); + first.ifPresent(extension -> addQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_CREATE, extension.getActions().get(PRE_CREATE.name())))); } + addQueryBuilder.append(ddl.createTable(change.getExpected(), false)); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - addQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_CREATE, "POST_CREATE")); + + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(POST_CREATE.name())).findFirst(); + first.ifPresent(extension -> addQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_CREATE, extension.getActions().get(POST_CREATE.name())))); } return addQueryBuilder.toString(); case ALTER: - StringBuilder alterQueryBuilder = new StringBuilder(); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - alterQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_ALTER, "PRE_ALTER")); - } - alterQueryBuilder.append(ddl.alterTable(change.getExpected(), change.getActual())); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - alterQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_ALTER, "POST_ALTER")); - } - return alterQueryBuilder.toString(); + StringBuilder alterQueryBuilder = new StringBuilder(); + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(PRE_ALTER.name())).findFirst(); + first.ifPresent(extension -> alterQueryBuilder.append(executeTableExtensions(change.getExpected(), PRE_ALTER, extension.getActions().get(PRE_ALTER.name())))); + } + + alterQueryBuilder.append(ddl.alterTable(change.getExpected(), change.getActual())); + + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(POST_ALTER.name())).findFirst(); + first.ifPresent(extension -> alterQueryBuilder.append(executeTableExtensions(change.getExpected(), POST_ALTER, extension.getActions().get(POST_ALTER.name())))); + } + return alterQueryBuilder.toString(); default: throw new RuntimeException("Operation " + change.getStatus() + " for table not supported"); } @@ -132,32 +145,47 @@ public String onColumnChange(ColumnChange change) { switch (change.getStatus()) { case ALTER: StringBuilder alterQueryBuilder = new StringBuilder(); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - alterQueryBuilder.append(executeColumnExtensions(change.getExpected(), PRE_ALTER, "PRE_ALTER")); + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(PRE_ALTER.name())).findFirst(); + first.ifPresent(extension -> alterQueryBuilder.append(executeColumnExtensions(change.getExpected(), PRE_ALTER, extension.getActions().get(PRE_ALTER.name())))); } + alterQueryBuilder.append(ddl.alterColumn(change)); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - alterQueryBuilder.append(executeColumnExtensions(change.getExpected(), POST_ALTER, "POST_ALTER")); + + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(POST_ALTER.name())).findFirst(); + first.ifPresent(extension -> alterQueryBuilder.append(executeColumnExtensions(change.getExpected(), POST_ALTER, extension.getActions().get(POST_ALTER.name())))); } return alterQueryBuilder.toString(); case DROP: StringBuilder dropQueryBuilder = new StringBuilder(); - if (change.getActual()!=null && change.getActual().getExtensions() != null) { - dropQueryBuilder.append(executeColumnExtensions(change.getActual(), PRE_DROP, "PRE_DROP")); + if (change.getActual() != null && change.getActual().getExtensions() != null) { + Optional first = change.getActual().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(PRE_DROP.name())).findFirst(); + first.ifPresent(extension -> dropQueryBuilder.append(executeColumnExtensions(change.getActual(), PRE_DROP, extension.getActions().get(PRE_DROP.name())))); } dropQueryBuilder.append(ddl.dropColumn(change)); - if (change.getActual()!=null && change.getActual().getExtensions() != null) { - dropQueryBuilder.append(executeColumnExtensions(change.getActual(), POST_DROP, "POST_DROP")); + if (change.getActual() != null && change.getActual().getExtensions() != null) { + Optional first = change.getActual().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(POST_DROP.name())).findFirst(); + first.ifPresent(extension -> dropQueryBuilder.append(executeColumnExtensions(change.getActual(), POST_DROP, extension.getActions().get(POST_DROP.name())))); } return dropQueryBuilder.toString(); case ADD: StringBuilder addQueryBuilder = new StringBuilder(); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - addQueryBuilder.append(executeColumnExtensions(change.getExpected(), PRE_CREATE, "PRE_CREATE")); + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(PRE_CREATE.name())).findFirst(); + first.ifPresent(extension -> addQueryBuilder.append(executeColumnExtensions(change.getExpected(), PRE_CREATE, extension.getActions().get(PRE_CREATE.name())))); } addQueryBuilder.append(ddl.addColumn(change)); - if (change.getExpected()!=null && change.getExpected().getExtensions() != null) { - addQueryBuilder.append(executeColumnExtensions(change.getExpected(), POST_CREATE, "POST_CREATE")); + + if (change.getExpected() != null && change.getExpected().getExtensions() != null) { + Optional first = change.getExpected().getExtensions().stream() + .filter(extension -> extension.getActions().containsKey(POST_CREATE.name())).findFirst(); + first.ifPresent(extension -> addQueryBuilder.append(executeColumnExtensions(change.getExpected(), POST_CREATE, extension.getActions().get(POST_CREATE.name())))); } return addQueryBuilder.toString(); default: @@ -166,7 +194,7 @@ public String onColumnChange(ColumnChange change) { } public String executeTableExtensions(Table table, OperationTypeEnum status, Object action) { - Optional> tableExtension = ModuleLoader.loadModuleByAnnotationClassValues("com.adaptivescale.rosetta.ddl.extensions.table", RosettaModuleTypes.DDL_EXTENSION_TABLE, "SQL"); + Optional> tableExtension = ModuleLoader.loadModuleByAnnotationClassValues(String.format("%s.%s",DDLExtensionTable.class.getPackageName(),"extensions.table") , RosettaModuleTypes.DDL_EXTENSION_TABLE, "SQL"); DDLExtensionTable ddlExtensionTable = null; if (tableExtension.isPresent()) { try { @@ -200,7 +228,7 @@ public String executeTableExtensions(Table table, OperationTypeEnum status, Obje } public String executeColumnExtensions(Column column, OperationTypeEnum status, Object action) { - Optional> columnExtension = ModuleLoader.loadModuleByAnnotationClassValues("com.adaptivescale.rosetta.ddl.extensions.column", RosettaModuleTypes.DDL_EXTENSION_COLUMN, "SQL"); + Optional> columnExtension = ModuleLoader.loadModuleByAnnotationClassValues(String.format("%s.%s",DDLExtensionColumn.class.getPackageName(),"extensions.column"), RosettaModuleTypes.DDL_EXTENSION_COLUMN, "SQL"); DDLExtensionColumn ddlExtensionColumn = null; if (columnExtension.isPresent()) { try { @@ -272,4 +300,4 @@ public String onViewChange(ViewChange change) { throw new RuntimeException("Operation " + change.getStatus() + " for view not supported"); } } -} +} \ No newline at end of file diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java index f5421b6d..f2b68218 100644 --- a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/column/DDLColumnChangeTest.java @@ -11,32 +11,32 @@ ) public class DDLColumnChangeTest implements DDLExtensionColumn { @Override - public String preCreateColumn(Column table, Object action) { + public String preCreateColumn(Column column, Object action) { return action.toString(); } @Override - public String postCreateColumn(Column table, Object action) { + public String postCreateColumn(Column column, Object action) { return action.toString(); } @Override - public String preDropColumn(Column table, Object action) { + public String preDropColumn(Column column, Object action) { return action.toString(); } @Override - public String postDropColumn(Column table, Object action) { + public String postDropColumn(Column column, Object action) { return action.toString(); } @Override - public String preAlterColumn(Column table, Object action) { + public String preAlterColumn(Column column, Object action) { return action.toString(); } @Override - public String postAlterColumn(Column table, Object action) { + public String postAlterColumn(Column column, Object action) { return action.toString(); } } diff --git a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java index db89ed31..32f5e187 100644 --- a/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java +++ b/ddl/src/main/java/com/adaptivescale/rosetta/ddl/extensions/table/DDLTableChangeTest.java @@ -7,37 +7,37 @@ @RosettaModule( name = "SQL", - type = RosettaModuleTypes.DDL_EXTENSION_COLUMN + type = RosettaModuleTypes.DDL_EXTENSION_TABLE ) public class DDLTableChangeTest implements DDLExtensionTable { @Override public String preCreateTable(Table table, Object action) { - return "preCreateTable"; + return action.toString(); } @Override public String postCreateTable(Table table, Object action) { - return "postCreateTable"; + return action.toString(); } @Override public String preDropTable(Table actual, Object action) { - return "preDropTable"; + return action.toString(); } @Override public String postDropTable(Table actual, Object action) { - return "postDropTable"; + return action.toString(); } @Override public String preAlterTable(Table expected, Object action) { - return "preAlterTable"; + return action.toString(); } @Override public String postAlterTable(Table expected, Object action) { - return "postAlterTable"; + return action.toString(); } } From 830e8351d5cd5c99fbbe52fe04d7c42cd77ab281 Mon Sep 17 00:00:00 2001 From: Femi3211 Date: Tue, 2 Jul 2024 13:44:29 +0200 Subject: [PATCH 3/3] added: documentation for Rosetta extension support --- README.md | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/README.md b/README.md index c04b0dc3..b08f320a 100644 --- a/README.md +++ b/README.md @@ -805,6 +805,107 @@ you can fix it by running the following command where your driver is located: ``` zip -d google-cloud-spanner-jdbc-2.6.2-single-jar-with-dependencies.jar 'META-INF/.SF' 'META-INF/.RSA' 'META-INF/*SF' ``` +## Rosetta Extensions Feature +### Overview +The Extensions feature in Rosetta allows users to append custom SQL code to the Data Definition Language (DDL) operations generated during the execution of the apply command. This feature enhances the flexibility and functionality of Rosetta by enabling custom SQL commands to be executed at various stages of the DDL lifecycle. + +### Supported Extensions + + +Currently, Rosetta supports the following extension: +- DDL_EXTENSION: This extension type allows the addition of custom SQL commands to the DDL operations. + + +### DDL_EXTENSION Commands + + +Users can specify custom SQL commands to be executed at different points in the DDL lifecycle using the following commands: +- PRE_CREATE: Execute SQL before a CREATE operation. +- PRE_ALTER: Execute SQL before an ALTER operation. +- PRE_DROP: Execute SQL before a DROP operation. +- POST_CREATE: Execute SQL after a CREATE operation. +- POST_ALTER: Execute SQL after an ALTER operation. +- POST_DROP: Execute SQL after a DROP operation. + +### Example Usage + +Below is an example of how to use the DDL_EXTENSION to append custom SQL code to a table creation operation in the model.yaml file. +```yaml +- name: "fullname" + typeName: "varchar" + ordinalPosition: 0 + primaryKeySequenceId: 0 + columnDisplaySize: 2147483647 + scale: 0 + precision: 2147483647 + columnProperties: [] + primaryKey: false + nullable: true + autoincrement: false + extensions: + - name: SQL + type: DDL_EXTENSION + actions: + POST_CREATE: UPDATE basic_library.authors SET fullname = CONCAT(name, ' ', surname) WHERE fullname IS NULL; +``` +### How to Use +1. Define the Extension in model.yaml: +- Add the extensions section under the column or table definition where the custom SQL needs to be applied. +- Specify the name as SQL and the type as DDL_EXTENSION. +3. Specify Actions: +- Under actions, define the SQL commands to be executed for the desired DDL operations (e.g., POST_CREATE, PRE_ALTER). +### Example Scenarios + + +#### Scenario 1: Custom SQL After Table Creation + +If you need to populate or update data in a newly created table immediately after its creation, you can use the POST_CREATE command: +```yaml +- name: "fullname" + typeName: "varchar" + ordinalPosition: 0 + primaryKeySequenceId: 0 + columnDisplaySize: 2147483647 + scale: 0 + precision: 2147483647 + columnProperties: [] + primaryKey: false + nullable: true + autoincrement: false + extensions: + - name: SQL + type: DDL_EXTENSION + actions: + POST_CREATE: UPDATE basic_library.authors SET fullname = CONCAT(name, ' ', surname) WHERE fullname IS NULL; +``` +#### Scenario 2: Custom SQL Before Table Alteration +To execute custom SQL before altering a table, use the PRE_ALTER command: +```yaml +- name: "fullname" + typeName: "varchar" + ordinalPosition: 0 + primaryKeySequenceId: 0 + columnDisplaySize: 2147483647 + scale: 0 + precision: 2147483647 + columnProperties: [] + primaryKey: false + nullable: true + autoincrement: false + extensions: + - name: SQL + type: DDL_EXTENSION + actions: + PRE_ALTER: CREATE TEMPORARY TABLE temp_authors AS SELECT * FROM authors; +``` +### Best Practices + +- Validation: Ensure that the custom SQL commands are valid and tested to avoid errors during the apply command execution. +- Performance: Consider the performance implications of the custom SQL, especially for large datasets. +- Security: Validate and sanitize custom SQL to prevent SQL injection and other security vulnerabilities. +### Conclusion + +The Extensions feature in Rosetta, particularly the DDL_EXTENSION, provides a powerful way to customize the DDL lifecycle with user-defined SQL commands. By leveraging this feature, users can enhance the functionality and control of their data operations, ensuring that specific actions are performed at key stages of the DDL execution process. ## Copyright and License Information Unless otherwise specified, all content, including all source code files and documentation files in this repository are: