diff --git a/pom.xml b/pom.xml index 64c62dbd..df279c99 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.exasol sql-statement-builder - 1.0.0 + 1.1.0 Exasol SQL Statement Builder This module provides a Builder for SQL statements that helps creating the correct structure and validates variable parts of the statements. https://github.com/exasol/sql-statement-builder diff --git a/src/main/java/com/exasol/sql/StatementFactory.java b/src/main/java/com/exasol/sql/StatementFactory.java index b648138c..4fd0c5df 100644 --- a/src/main/java/com/exasol/sql/StatementFactory.java +++ b/src/main/java/com/exasol/sql/StatementFactory.java @@ -2,6 +2,7 @@ import com.exasol.sql.ddl.create.CreateSchema; import com.exasol.sql.ddl.create.CreateTable; +import com.exasol.sql.ddl.drop.DropSchema; import com.exasol.sql.ddl.drop.DropTable; import com.exasol.sql.dml.Insert; import com.exasol.sql.dql.Select; @@ -76,4 +77,14 @@ public CreateSchema createSchema(String schemaName) { public DropTable dropTable(final String tableName) { return new DropTable(tableName); } + + /** + * Create a {@link DropSchema} statement + * + * @param schemaName name of the schema to drop + * @return a new instance of a {@link DropSchema} statement + */ + public DropSchema dropSchema(String schemaName) { + return new DropSchema(schemaName); + } } diff --git a/src/main/java/com/exasol/sql/ddl/Schema.java b/src/main/java/com/exasol/sql/ddl/Schema.java index e3192553..50ae011d 100644 --- a/src/main/java/com/exasol/sql/ddl/Schema.java +++ b/src/main/java/com/exasol/sql/ddl/Schema.java @@ -3,6 +3,7 @@ import com.exasol.sql.AbstractFragment; import com.exasol.sql.Fragment; import com.exasol.sql.ddl.create.CreateSchemaVisitor; +import com.exasol.sql.ddl.drop.DropSchemaVisitor; /** * This class represents a {@link Schema} in an SQL Statement @@ -33,4 +34,8 @@ public String getName() { public void accept(CreateSchemaVisitor visitor) { visitor.visit(this); } + + public void accept(DropSchemaVisitor visitor) { + visitor.visit(this); + } } diff --git a/src/main/java/com/exasol/sql/ddl/create/rendering/CreateSchemaRenderer.java b/src/main/java/com/exasol/sql/ddl/create/rendering/CreateSchemaRenderer.java index cbdbbecf..22b9ba52 100644 --- a/src/main/java/com/exasol/sql/ddl/create/rendering/CreateSchemaRenderer.java +++ b/src/main/java/com/exasol/sql/ddl/create/rendering/CreateSchemaRenderer.java @@ -22,7 +22,7 @@ public CreateSchemaRenderer(final StringRendererConfig config) { /** * Create an {@link CreateSchemaRenderer} using the default renderer configuration * - * @return insert renderer + * @return CREATE SCHEMA renderer */ public static CreateSchemaRenderer create() { return new CreateSchemaRenderer(StringRendererConfig.createDefault()); @@ -32,7 +32,7 @@ public static CreateSchemaRenderer create() { * Create an {@link CreateSchemaRenderer} * * @param config renderer configuration - * @return create schema renderer + * @return CREATE SCHEMA renderer */ public static CreateSchemaRenderer create(final StringRendererConfig config) { return new CreateSchemaRenderer(config); diff --git a/src/main/java/com/exasol/sql/ddl/create/rendering/CreateTableRenderer.java b/src/main/java/com/exasol/sql/ddl/create/rendering/CreateTableRenderer.java index 2a953b09..c5eda305 100644 --- a/src/main/java/com/exasol/sql/ddl/create/rendering/CreateTableRenderer.java +++ b/src/main/java/com/exasol/sql/ddl/create/rendering/CreateTableRenderer.java @@ -23,7 +23,7 @@ public CreateTableRenderer(final StringRendererConfig config) { /** * Create an {@link CreateTableRenderer} using the default renderer configuration * - * @return insert renderer + * @return CREATE TABLE renderer */ public static CreateTableRenderer create() { return new CreateTableRenderer(StringRendererConfig.createDefault()); @@ -33,7 +33,7 @@ public static CreateTableRenderer create() { * Create an {@link CreateTableRenderer} * * @param config renderer configuration - * @return create table renderer + * @return CREATE TABLE renderer */ public static CreateTableRenderer create(final StringRendererConfig config) { return new CreateTableRenderer(config); diff --git a/src/main/java/com/exasol/sql/ddl/drop/Cascade.java b/src/main/java/com/exasol/sql/ddl/drop/Cascade.java new file mode 100644 index 00000000..438b8a9b --- /dev/null +++ b/src/main/java/com/exasol/sql/ddl/drop/Cascade.java @@ -0,0 +1,23 @@ +package com.exasol.sql.ddl.drop; + +import com.exasol.sql.AbstractFragment; +import com.exasol.sql.Fragment; + +/** + * This class represents CASCADE clause in DROP SCHEMA SQL statement + */ +public final class Cascade extends AbstractFragment implements DropSchemaFragment { + /** + * Create an instance of {@link Cascade} class + * + * @param root root SQL statement this fragment belongs to + */ + protected Cascade(final Fragment root) { + super(root); + } + + @Override + public void accept(final DropSchemaVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/com/exasol/sql/ddl/drop/CascadeConstraints.java b/src/main/java/com/exasol/sql/ddl/drop/CascadeConstraints.java index 003ed20f..94726eb8 100644 --- a/src/main/java/com/exasol/sql/ddl/drop/CascadeConstraints.java +++ b/src/main/java/com/exasol/sql/ddl/drop/CascadeConstraints.java @@ -4,7 +4,7 @@ import com.exasol.sql.Fragment; /** - * This class represents "cascade constraints" expression in DROP TABLE SQL statement + * This class represents CASCADE CONSTRAINTS clause in DROP TABLE SQL statement */ public final class CascadeConstraints extends AbstractFragment implements DropTableFragment { /** diff --git a/src/main/java/com/exasol/sql/ddl/drop/DropSchema.java b/src/main/java/com/exasol/sql/ddl/drop/DropSchema.java new file mode 100644 index 00000000..32df79d8 --- /dev/null +++ b/src/main/java/com/exasol/sql/ddl/drop/DropSchema.java @@ -0,0 +1,104 @@ +package com.exasol.sql.ddl.drop; + +import com.exasol.sql.AbstractFragment; +import com.exasol.sql.SqlStatement; +import com.exasol.sql.ddl.Schema; + +/** + * This class implements an SQL {@link DropSchema} statement + */ +public class DropSchema extends AbstractFragment implements SqlStatement, DropSchemaFragment { + private Schema schema; + private Cascade cascade; + private Restrict restrict; + private boolean ifExists = false; + + /** + * Create a new instance of an {@link DropSchema} statement + * + * @param schemaName name of the table to drop + */ + public DropSchema(final String schemaName) { + super(null); + this.schema = new Schema(this, schemaName); + } + + /** + * Add IF EXISTS clause into a DROP SCHEMA statement + * + * @return this for fluent programming + */ + public synchronized DropSchema ifExists() { + if (!this.ifExists) { + this.ifExists = true; + } + return this; + } + + /** + * Add CASCADE clause into a DROP SCHEMA statement + * + * @return this for fluent programming + */ + public synchronized DropSchema cascade() { + cascade = new Cascade(this); + return this; + } + + /** + * Add RESTRICT clause into a DROP SCHEMA statement + * + * @return this for fluent programming + */ + public synchronized DropSchema restrict() { + restrict = new Restrict(this); + return this; + } + + /** + * Get a schema name + * + * @return schema name + */ + public String getSchemaName() { + return schema.getName(); + } + + public Cascade getCascade() { + return cascade; + } + + public Restrict getRestrict() { + return restrict; + } + + @Override + public void accept(DropSchemaVisitor visitor) { + validateCascadeAndRestrict(); + visitor.visit(this); + this.schema.accept(visitor); + if (cascade != null) { + cascade.accept(visitor); + } + if (restrict != null) { + restrict.accept(visitor); + } + } + + /** + * Get true when IF EXISTS clause presents + * + * @return if exists + */ + public boolean getIfExists() { + return ifExists; + } + + private void validateCascadeAndRestrict() { + if (cascade != null && restrict != null) { + throw new IllegalArgumentException( + "DROP SCHEMA expression must not contain CASCADE and RESTRICT clauses at the came time. " + + "Use only one of them."); + } + } +} diff --git a/src/main/java/com/exasol/sql/ddl/drop/DropSchemaFragment.java b/src/main/java/com/exasol/sql/ddl/drop/DropSchemaFragment.java new file mode 100644 index 00000000..1bbedc74 --- /dev/null +++ b/src/main/java/com/exasol/sql/ddl/drop/DropSchemaFragment.java @@ -0,0 +1,15 @@ +package com.exasol.sql.ddl.drop; + +import com.exasol.sql.Fragment; + +/** + * This is the common interface for all fragments of a DROP SCHEMA statement. + */ +public interface DropSchemaFragment extends Fragment { + /** + * Accept a visitor (e.g. a renderer or validator) + * + * @param visitor visitor to accept + */ + public void accept(DropSchemaVisitor visitor); +} diff --git a/src/main/java/com/exasol/sql/ddl/drop/DropSchemaVisitor.java b/src/main/java/com/exasol/sql/ddl/drop/DropSchemaVisitor.java new file mode 100644 index 00000000..4388c899 --- /dev/null +++ b/src/main/java/com/exasol/sql/ddl/drop/DropSchemaVisitor.java @@ -0,0 +1,13 @@ +package com.exasol.sql.ddl.drop; + +import com.exasol.sql.ddl.Schema; + +public interface DropSchemaVisitor { + public void visit(DropSchema dropSchema); + + public void visit(Schema schema); + + public void visit(Cascade cascade); + + public void visit(Restrict restrict); +} diff --git a/src/main/java/com/exasol/sql/ddl/drop/DropTable.java b/src/main/java/com/exasol/sql/ddl/drop/DropTable.java index 585c4e38..790ae426 100644 --- a/src/main/java/com/exasol/sql/ddl/drop/DropTable.java +++ b/src/main/java/com/exasol/sql/ddl/drop/DropTable.java @@ -30,7 +30,7 @@ public void accept(final DropTableVisitor visitor) { } /** - * Add "if exists" expression into a DROP TABLE statement + * Add IF EXISTS clause into a DROP TABLE statement * * @return this for fluent programming */ @@ -42,7 +42,7 @@ public synchronized DropTable ifExists() { } /** - * Add "cascade constraints" expression into a DROP TABLE statement + * Add CASCADE CONSTRAINTS clause into a DROP TABLE statement * * @return this for fluent programming */ @@ -52,7 +52,7 @@ public DropTable cascadeConstraints() { } /** - * Get true when "if exists" expression presents + * Get true when IF EXISTS clause presents * * @return if exists */ diff --git a/src/main/java/com/exasol/sql/ddl/drop/Restrict.java b/src/main/java/com/exasol/sql/ddl/drop/Restrict.java new file mode 100644 index 00000000..dd236ced --- /dev/null +++ b/src/main/java/com/exasol/sql/ddl/drop/Restrict.java @@ -0,0 +1,23 @@ +package com.exasol.sql.ddl.drop; + +import com.exasol.sql.AbstractFragment; +import com.exasol.sql.Fragment; + +/** + * This class represents RESTRICT clause in DROP SCHEMA SQL statement + */ +public final class Restrict extends AbstractFragment implements DropSchemaFragment { + /** + * Create an instance of {@link Restrict} class + * + * @param root root SQL statement this fragment belongs to + */ + protected Restrict(final Fragment root) { + super(root); + } + + @Override + public void accept(final DropSchemaVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/com/exasol/sql/ddl/drop/rendering/DropSchemaRenderer.java b/src/main/java/com/exasol/sql/ddl/drop/rendering/DropSchemaRenderer.java new file mode 100644 index 00000000..4fb11147 --- /dev/null +++ b/src/main/java/com/exasol/sql/ddl/drop/rendering/DropSchemaRenderer.java @@ -0,0 +1,66 @@ +package com.exasol.sql.ddl.drop.rendering; + +import com.exasol.sql.ddl.Schema; +import com.exasol.sql.ddl.drop.*; +import com.exasol.sql.rendering.AbstractFragmentRenderer; +import com.exasol.sql.rendering.StringRendererConfig; + +/** + * The {@link DropSchemaRenderer} turns SQL statement structures in to SQL strings. + */ +public class DropSchemaRenderer extends AbstractFragmentRenderer implements DropSchemaVisitor { + /** + * Create a new {@link DropSchemaRenderer} with custom render settings. + * + * @param config render configuration settings + */ + public DropSchemaRenderer(final StringRendererConfig config) { + super(config); + } + + /** + * Create an {@link DropSchemaRenderer} using the default renderer configuration + * + * @return DROP SCHEMA renderer + */ + public static DropSchemaRenderer create() { + return new DropSchemaRenderer(StringRendererConfig.createDefault()); + } + + /** + * Create an {@link DropSchemaRenderer} + * + * @param config renderer configuration + * @return DROP SCHEMA renderer + */ + public static DropSchemaRenderer create(final StringRendererConfig config) { + return new DropSchemaRenderer(config); + } + + @Override + public void visit(DropSchema dropSchema) { + appendKeyWord("DROP SCHEMA "); + if (dropSchema.getIfExists()) { + appendKeyWord("IF EXISTS "); + } + setLastVisited(dropSchema); + } + + @Override + public void visit(Schema schema) { + appendAutoQuoted(schema.getName()); + setLastVisited(schema); + } + + @Override + public void visit(Cascade cascade) { + appendKeyWord(" CASCADE"); + setLastVisited(cascade); + } + + @Override + public void visit(Restrict restrict) { + appendKeyWord(" RESTRICT"); + setLastVisited(restrict); + } +} diff --git a/src/main/java/com/exasol/sql/ddl/drop/rendering/DropTableRenderer.java b/src/main/java/com/exasol/sql/ddl/drop/rendering/DropTableRenderer.java index 455f806b..284a8327 100644 --- a/src/main/java/com/exasol/sql/ddl/drop/rendering/DropTableRenderer.java +++ b/src/main/java/com/exasol/sql/ddl/drop/rendering/DropTableRenderer.java @@ -21,7 +21,7 @@ public DropTableRenderer(final StringRendererConfig config) { /** * Create an {@link DropTableRenderer} using the default renderer configuration * - * @return insert renderer + * @return DROP TABLE renderer */ public static DropTableRenderer create() { return new DropTableRenderer(StringRendererConfig.createDefault()); @@ -31,7 +31,7 @@ public static DropTableRenderer create() { * Create an {@link DropTableRenderer} * * @param config renderer configuration - * @return create table renderer + * @return DROP TABLE renderer */ public static DropTableRenderer create(final StringRendererConfig config) { return new DropTableRenderer(config); diff --git a/src/test/java/com/exasol/hamcrest/SqlFragmentRenderResultMatcher.java b/src/test/java/com/exasol/hamcrest/SqlFragmentRenderResultMatcher.java index c954cf7a..000a6145 100644 --- a/src/test/java/com/exasol/hamcrest/SqlFragmentRenderResultMatcher.java +++ b/src/test/java/com/exasol/hamcrest/SqlFragmentRenderResultMatcher.java @@ -3,7 +3,9 @@ import com.exasol.sql.ddl.create.*; import com.exasol.sql.ddl.create.rendering.CreateSchemaRenderer; import com.exasol.sql.ddl.create.rendering.CreateTableRenderer; +import com.exasol.sql.ddl.drop.DropSchemaFragment; import com.exasol.sql.ddl.drop.DropTableFragment; +import com.exasol.sql.ddl.drop.rendering.DropSchemaRenderer; import com.exasol.sql.ddl.drop.rendering.DropTableRenderer; import org.hamcrest.Description; @@ -59,6 +61,10 @@ public boolean matchesSafely(final Fragment fragment) { final CreateSchemaRenderer renderer = new CreateSchemaRenderer(this.config); ((CreateSchemaFragment) root).accept(renderer); this.renderedText = renderer.render(); + } else if (root instanceof DropSchemaFragment) { + final DropSchemaRenderer renderer = new DropSchemaRenderer(this.config); + ((DropSchemaFragment) root).accept(renderer); + this.renderedText = renderer.render(); } else { throw new UnsupportedOperationException( "Don't know how to render fragment of type\"" + root.getClass().getName() + "\"."); diff --git a/src/test/java/com/exasol/sql/ddl/create/TestCreateSchema.java b/src/test/java/com/exasol/sql/ddl/create/TestCreateSchema.java index c95e1fee..a36678d3 100644 --- a/src/test/java/com/exasol/sql/ddl/create/TestCreateSchema.java +++ b/src/test/java/com/exasol/sql/ddl/create/TestCreateSchema.java @@ -17,7 +17,7 @@ void setUp() { } @Test - void getTableName() { + void getSchemaName() { assertThat(this.createSchema.getSchemaName(), equalTo(TEST_SCHEMA_NAME)); } } \ No newline at end of file diff --git a/src/test/java/com/exasol/sql/ddl/drop/TestDropSchema.java b/src/test/java/com/exasol/sql/ddl/drop/TestDropSchema.java new file mode 100644 index 00000000..dc857cca --- /dev/null +++ b/src/test/java/com/exasol/sql/ddl/drop/TestDropSchema.java @@ -0,0 +1,45 @@ +package com.exasol.sql.ddl.drop; + +import com.exasol.sql.StatementFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.*; + +class TestDropSchema { + private static final String TEST_SCHEMA_NAME = "test schema name"; + private DropSchema dropSchema; + + @BeforeEach + void setUp() { + dropSchema = StatementFactory.getInstance().dropSchema(TEST_SCHEMA_NAME); + } + + @Test + void getTableName() { + assertThat(this.dropSchema.getSchemaName(), equalTo(TEST_SCHEMA_NAME)); + } + + @Test + void ifExists() { + assertFalse(this.dropSchema.getIfExists()); + this.dropSchema.ifExists(); + assertTrue(this.dropSchema.getIfExists()); + } + + @Test + void setCascade() { + assertNull(this.dropSchema.getCascade()); + this.dropSchema.cascade(); + assertNotNull(this.dropSchema.getCascade()); + } + + @Test + void setRestrict() { + assertNull(this.dropSchema.getRestrict()); + this.dropSchema.restrict(); + assertNotNull(this.dropSchema.getRestrict()); + } +} \ No newline at end of file diff --git a/src/test/java/com/exasol/sql/ddl/drop/rendering/TestDropSchemaRenderer.java b/src/test/java/com/exasol/sql/ddl/drop/rendering/TestDropSchemaRenderer.java new file mode 100644 index 00000000..c3d2be1e --- /dev/null +++ b/src/test/java/com/exasol/sql/ddl/drop/rendering/TestDropSchemaRenderer.java @@ -0,0 +1,26 @@ +package com.exasol.sql.ddl.drop.rendering; + +import com.exasol.sql.StatementFactory; +import com.exasol.sql.ddl.drop.DropSchema; +import com.exasol.sql.rendering.StringRendererConfig; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.core.StringStartsWith.startsWith; + +class TestDropSchemaRenderer { + @Test + void testCreateWithDefaultConfig() { + assertThat(DropSchemaRenderer.create(), instanceOf(DropSchemaRenderer.class)); + } + + @Test + void testCreateWithConfig() { + final StringRendererConfig config = StringRendererConfig.builder().lowerCase(true).build(); + final DropSchemaRenderer renderer = DropSchemaRenderer.create(config); + final DropSchema dropSchema = StatementFactory.getInstance().dropSchema("test name"); + dropSchema.accept(renderer); + assertThat(renderer.render(), startsWith("drop schema")); + } +} diff --git a/src/test/java/com/exasol/sql/ddl/drop/rendering/TestDropSchemaRendering.java b/src/test/java/com/exasol/sql/ddl/drop/rendering/TestDropSchemaRendering.java new file mode 100644 index 00000000..623c4f39 --- /dev/null +++ b/src/test/java/com/exasol/sql/ddl/drop/rendering/TestDropSchemaRendering.java @@ -0,0 +1,47 @@ +package com.exasol.sql.ddl.drop.rendering; + +import com.exasol.sql.StatementFactory; +import com.exasol.sql.ddl.drop.DropSchema; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static com.exasol.hamcrest.SqlFragmentRenderResultMatcher.rendersTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class TestDropSchemaRendering { + private static final String SCHEMA_NAME = "testName"; + private DropSchema dropSchema; + + @BeforeEach + void beforeEach() { + this.dropSchema = StatementFactory.getInstance().dropSchema(SCHEMA_NAME); + } + + @Test + void testDropSchema() { + assertThat(this.dropSchema, rendersTo("DROP SCHEMA testName")); + } + + @Test + void testDropSchemaIfExists() { + assertThat(this.dropSchema.ifExists(), rendersTo("DROP SCHEMA IF EXISTS testName")); + } + + @Test + void testDropSchemaCascade() { + assertThat(this.dropSchema.cascade(), rendersTo("DROP SCHEMA testName CASCADE")); + } + + @Test + void testDropSchemaRestrict() { + assertThat(this.dropSchema.restrict(), rendersTo("DROP SCHEMA testName RESTRICT")); + } + + @Test + void testDropSchemaCascadeAndRestrictThrowsException() { + final DropSchemaRenderer renderer = DropSchemaRenderer.create(); + this.dropSchema.restrict().cascade(); + assertThrows(IllegalArgumentException.class, () -> dropSchema.accept(renderer)); + } +}