diff --git a/CHANGELOG.md b/CHANGELOG.md index ce440caf..4df391ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,13 @@ ### Functionality Improvements #182: Adding Hibernate reverse-engineering API. See [ORM Integration docs](https://goldmansachs.github.io/obevo/orm-integration.html) for more details. #221 #223 #225: Oracle reverse-engineering improvements - unicode characters, nested tables, types, comments +#227: PostgreSQL improvements for kata - reverse-engineering, in-memory databases ### Technical Improvements +#227: Upgrading checkstyle version to avoid security prompts at Github site ### Bug Fixes +#227: Fixed drop behavior of PostgreSQL for multiple views that depended on each other ## 7.0.2 diff --git a/obevo-db-impls/obevo-db-postgresql/obevo-db-postgresql.iml b/obevo-db-impls/obevo-db-postgresql/obevo-db-postgresql.iml index 19eb5bfe..78c1e2b2 100644 --- a/obevo-db-impls/obevo-db-postgresql/obevo-db-postgresql.iml +++ b/obevo-db-impls/obevo-db-postgresql/obevo-db-postgresql.iml @@ -78,6 +78,10 @@ + + + + diff --git a/obevo-db-impls/obevo-db-postgresql/pom.xml b/obevo-db-impls/obevo-db-postgresql/pom.xml index 09914838..2b2db99c 100644 --- a/obevo-db-impls/obevo-db-postgresql/pom.xml +++ b/obevo-db-impls/obevo-db-postgresql/pom.xml @@ -49,6 +49,21 @@ postgresql + + com.goldmansachs.obevo + obevo-db-h2 + ${project.version} + true + + + + com.goldmansachs.obevo + obevo-db-hsql + ${project.version} + true + + + com.goldmansachs.obevo obevo-db-internal-test-helper diff --git a/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlDbPlatform.java b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlDbPlatform.java index 43f290c4..97596992 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlDbPlatform.java +++ b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlDbPlatform.java @@ -20,6 +20,8 @@ import com.gs.obevo.db.api.appdata.GrantTargetType; import com.gs.obevo.db.api.platform.DbChangeType; import com.gs.obevo.db.api.platform.DbChangeTypeImpl; +import com.gs.obevo.db.api.platform.DbPlatform; +import com.gs.obevo.db.api.platform.DbTranslationDialect; import com.gs.obevo.db.apps.reveng.AbstractDdlReveng; import com.gs.obevo.db.impl.platforms.AbstractDbPlatform; import org.eclipse.collections.api.block.function.Function; @@ -116,4 +118,13 @@ public ImmutableSet getRequiredValidationObjectTypes() { public AbstractDdlReveng getDdlReveng() { return new PostgreSqlPgDumpReveng(); } + + @Override + public DbTranslationDialect getDbTranslationDialect(DbPlatform targetDialect) { + if (targetDialect.getClass().getName().equals("com.gs.obevo.db.impl.platforms.hsql.HsqlDbPlatform")) { + return new PostgreSqlToHsqlTranslationDialect(); + } else { + return super.getDbTranslationDialect(targetDialect); + } + } } diff --git a/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlPgDumpReveng.java b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlPgDumpReveng.java index 59a27338..f9729559 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlPgDumpReveng.java +++ b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlPgDumpReveng.java @@ -105,7 +105,8 @@ protected boolean doRevengOrInstructions(PrintStream out, AquaRevengArgs args, F private String getCommandWithDefaults(boolean container, AquaRevengArgs args, File interimDir, String username, String password, String dbHost, String dbPort, String dbName, String dbSchema, String outputDirectory) { String prefix = container ? "docker exec $CONTAINER_NAME " : ""; - String fileSuffix = container ? "> " + interimDir.getAbsolutePath() : " -f " + interimDir.getAbsolutePath(); + String fileSuffix = container ? "> " : " -f "; + fileSuffix += new File(interimDir, "revengoutput.txt").getAbsolutePath(); return prefix + "pg_dump -O -s --no-privileges" + " -h " + ObjectUtils.defaultIfNull(args.getDbHost(), dbHost) + " -p " + ObjectUtils.defaultIfNull(args.getDbPort(), dbPort) + diff --git a/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlToH2TranslationDialect.java b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlToH2TranslationDialect.java new file mode 100644 index 00000000..d2efcbbd --- /dev/null +++ b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlToH2TranslationDialect.java @@ -0,0 +1,27 @@ +/** + * Copyright 2017 Goldman Sachs. + * 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 + * + * http://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 com.gs.obevo.db.impl.platforms.postgresql; + +import com.gs.obevo.db.impl.platforms.DefaultDbTranslationDialect; +import org.eclipse.collections.api.list.ImmutableList; +import org.eclipse.collections.impl.factory.Lists; + +public class PostgreSqlToH2TranslationDialect extends DefaultDbTranslationDialect { + @Override + public ImmutableList getInitSqls() { + return Lists.immutable.with("SET MODE PostgreSQL"); + } +} diff --git a/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlToHsqlTranslationDialect.java b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlToHsqlTranslationDialect.java new file mode 100644 index 00000000..df351769 --- /dev/null +++ b/obevo-db-impls/obevo-db-postgresql/src/main/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlToHsqlTranslationDialect.java @@ -0,0 +1,92 @@ +/** + * Copyright 2017 Goldman Sachs. + * 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 + * + * http://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 com.gs.obevo.db.impl.platforms.postgresql; + +import java.sql.Connection; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.gs.obevo.api.platform.ChangeType; +import com.gs.obevo.db.impl.core.jdbc.JdbcHelper; +import com.gs.obevo.db.impl.platforms.DefaultDbTranslationDialect; +import com.gs.obevo.db.impl.platforms.sqltranslator.InMemoryTranslator; +import com.gs.obevo.db.impl.platforms.sqltranslator.PostColumnSqlTranslator; +import com.gs.obevo.db.impl.platforms.sqltranslator.PreParsedSqlTranslator; +import com.gs.obevo.db.impl.platforms.sqltranslator.SqlTranslatorConfigHelper; +import com.gs.obevo.db.sqlparser.syntaxparser.CreateTable; +import com.gs.obevo.db.sqlparser.syntaxparser.CreateTableColumn; +import com.gs.obevo.impl.PrepareDbChange; +import org.eclipse.collections.api.list.ImmutableList; +import org.eclipse.collections.api.set.ImmutableSet; +import org.eclipse.collections.impl.factory.Lists; +import org.eclipse.collections.impl.factory.Sets; + +public class PostgreSqlToHsqlTranslationDialect extends DefaultDbTranslationDialect { + private final PostColumnSqlTranslator replaceNextvalWithIdentity = new PostColumnSqlTranslator() { + private final Pattern defaultPattern = Pattern.compile("(?i)default\\s+nextval.*", Pattern.DOTALL); + + @Override + public String handlePostColumnText(String postColumnText, CreateTableColumn column, CreateTable table) { + Matcher defaultMatcher = defaultPattern.matcher(postColumnText); + if (defaultMatcher.find()) { + postColumnText = defaultMatcher.replaceFirst("IDENTITY"); + } + + return postColumnText; + } + }; + + private final PreParsedSqlTranslator substituteCreateOrReplace = new PreParsedSqlTranslator() { + Pattern pattern = Pattern.compile("(?i)^\\s*create\\s+or\\s+replace\\s+", Pattern.DOTALL); + @Override + public String preprocessSql(String sql) { + Matcher matcher = pattern.matcher(sql); + if (matcher.find()) { + sql = matcher.replaceFirst("create "); + } + return sql; + } + }; + + @Override + public ImmutableList getInitSqls() { + return Lists.immutable.with( + "SET DATABASE SQL SYNTAX PGS TRUE" + , "SET DATABASE TRANSACTION CONTROL MVCC" + ); + } + + @Override + public ImmutableList getAdditionalTranslators() { + SqlTranslatorConfigHelper configHelper = SqlTranslatorConfigHelper.createInMemoryDefault(); + + configHelper.getPreParsedSqlTranslators() + .with(substituteCreateOrReplace); + configHelper.getPostColumnSqlTranslators() + .with(replaceNextvalWithIdentity); + return Lists.immutable.with(new InMemoryTranslator(configHelper)); + } + + @Override + public void initSchema(JdbcHelper jdbc, Connection conn) { + updateAndIgnoreException(conn, jdbc, "create type int4 as integer"); + } + + @Override + public ImmutableSet getDisabledChangeTypeNames() { + return Sets.immutable.of(ChangeType.FUNCTION_STR, ChangeType.SP_STR); + } +} diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlInMemConversionTest.java b/obevo-db-impls/obevo-db-postgresql/src/test/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlInMemConversionTest.java new file mode 100644 index 00000000..c6d4380d --- /dev/null +++ b/obevo-db-impls/obevo-db-postgresql/src/test/java/com/gs/obevo/db/impl/platforms/postgresql/PostgreSqlInMemConversionTest.java @@ -0,0 +1,53 @@ +/** + * Copyright 2017 Goldman Sachs. + * 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 + * + * http://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 com.gs.obevo.db.impl.platforms.postgresql; + +import com.gs.obevo.db.api.platform.DbDeployerAppContext; +import com.gs.obevo.db.impl.platforms.h2.H2DbPlatform; +import com.gs.obevo.db.impl.platforms.hsql.HsqlDbPlatform; +import com.gs.obevo.db.unittest.UnitTestDbBuilder; +import org.junit.Test; + +public class PostgreSqlInMemConversionTest { + @Test + public void testInMemoryHsql() { + DbDeployerAppContext context = UnitTestDbBuilder.newBuilder() + .setSourcePath("platforms/postgresql/example1/step1/system-config-inmem.xml") + .setReferenceEnvName("unittestrefhsql") + .setDbPlatform(new HsqlDbPlatform()) + .setDbServer("mydb2testHsql") + .buildContext(); + context.setupEnvInfra(); + context.cleanAndDeploy(); + + // TODO add assertions + } + + // Implementation for H2 TBD +// @Test +// public void testInMemoryH2() { +// DbDeployerAppContext context = UnitTestDbBuilder.newBuilder() +// .setSourcePath("platforms/postgresql/example1/step1/system-config-inmem.xml") +// .setReferenceEnvName("unittestrefh2") +// .setDbPlatform(new H2DbPlatform()) +// .setDbServer("mydb2testH2") +// .buildContext(); +// context.setupEnvInfra(); +// context.cleanAndDeploy(); +// +// // TODO add assertions +// } +} diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_A.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_A.ddl index effbdcbb..2891013b 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_A.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_A.ddl @@ -1,29 +1,29 @@ -//// CHANGE name=chng1 -CREATE TABLE TABLE_A ( - A_ID INT NOT NULL, - B_ID INT NOT NULL, - STRING_FIELD VARCHAR(30) NULL, - TIMESTAMP_FIELD TIMESTAMP NULL, - PRIMARY KEY (A_ID) -) -GO - -//// CHANGE name=emptychange -//// CHANGE name=emptychange2 - - -//// CHANGE FK name=chng2 -ALTER TABLE TABLE_A ADD FOREIGN KEY (B_ID) REFERENCES TABLE_B(B_ID) -GO -//// CHANGE name=chng3 -ALTER TABLE TABLE_A ADD COLUMN C_ID INT NULL -GO -//// CHANGE name=extra1 -ALTER TABLE TABLE_A ADD COLUMN EXTRA1 INT NULL -GO -//// CHANGE name=extra2 -ALTER TABLE TABLE_A ADD COLUMN EXTRA2 INT NULL -GO -//// CHANGE name=extra3 -ALTER TABLE TABLE_A ADD COLUMN EXTRA3 INT NULL -GO +//// CHANGE name=chng1 +CREATE TABLE TABLE_A ( + A_ID INT NOT NULL, + B_ID INT NOT NULL, + STRING_FIELD VARCHAR(30) NULL, + TIMESTAMP_FIELD TIMESTAMP NULL, + PRIMARY KEY (A_ID) +) WITHOUT OIDS +GO + +//// CHANGE name=emptychange +//// CHANGE name=emptychange2 + + +//// CHANGE FK name=chng2 +ALTER TABLE TABLE_A ADD FOREIGN KEY (B_ID) REFERENCES TABLE_B(B_ID) +GO +//// CHANGE name=chng3 +ALTER TABLE TABLE_A ADD COLUMN C_ID INT NULL +GO +//// CHANGE name=extra1 +ALTER TABLE TABLE_A ADD COLUMN EXTRA1 INT NULL +GO +//// CHANGE name=extra2 +ALTER TABLE TABLE_A ADD COLUMN EXTRA2 INT NULL +GO +//// CHANGE name=extra3 +ALTER TABLE TABLE_A ADD COLUMN EXTRA3 INT NULL +GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_B.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_B.ddl index cff127c4..81b93691 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_B.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_B.ddl @@ -1,5 +1,5 @@ -//// CHANGE name=chng1 -CREATE TABLE TABLE_B ( - B_ID INT NOT NULL, - PRIMARY KEY (B_ID) -) +//// CHANGE name=chng1 +CREATE TABLE TABLE_B ( + B_ID INT NOT NULL, + PRIMARY KEY (B_ID) +) WITHOUT OIDS diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_SPECIAL_COL.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_SPECIAL_COL.ddl index 3114fe83..71698aea 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_SPECIAL_COL.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TABLE_SPECIAL_COL.ddl @@ -3,5 +3,5 @@ CREATE TABLE TABLE_SPECIAL_COL ( UUID_PK UUID NOT NULL, STR1 VARCHAR(30) NULL, PRIMARY KEY (UUID_PK) -) +) WITHOUT OIDS GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TAB_WITH_SEQ.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TAB_WITH_SEQ.ddl index c6e7ed25..24889b18 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TAB_WITH_SEQ.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/table/TAB_WITH_SEQ.ddl @@ -1,8 +1,8 @@ -//// METADATA excludePlatforms=REDSHIFT -//// CHANGE name=chng1 -CREATE TABLE TAB_WITH_SEQ ( - ID int4 NOT NULL DEFAULT nextval('MYSEQ1'::regclass), - FIELD1 INT NULL, - PRIMARY KEY (ID) -) -GO +//// METADATA excludePlatforms=REDSHIFT +//// CHANGE name=chng1 +CREATE TABLE TAB_WITH_SEQ ( + ID int4 NOT NULL DEFAULT nextval('MYSEQ1'::regclass), + FIELD1 INT NULL, + PRIMARY KEY (ID) +) WITHOUT OIDS +GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/usertype/usertype0.hsql.sql b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/usertype/usertype0.hsql.sql new file mode 100644 index 00000000..93efe056 --- /dev/null +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/usertype/usertype0.hsql.sql @@ -0,0 +1,3 @@ +//// METADATA includePlatforms="HSQL" +CREATE TYPE usertype0 AS VARCHAR(1); +GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/usertype/usertype0.sql b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/usertype/usertype0.sql index bfe03d74..bf6ab05b 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/usertype/usertype0.sql +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/schema1/usertype/usertype0.sql @@ -1,3 +1,4 @@ +//// METADATA excludePlatforms="HSQL" CREATE TYPE usertype0 AS ENUM ( '1', '2', diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/system-config-inmem.xml b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/system-config-inmem.xml new file mode 100644 index 00000000..2a94b414 --- /dev/null +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step1/system-config-inmem.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_A.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_A.ddl index a8382583..3b88b31f 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_A.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_A.ddl @@ -1,32 +1,32 @@ -//// CHANGE name=chng1 -CREATE TABLE TABLE_A ( - A_ID INT NOT NULL, - B_ID INT NOT NULL, - STRING_FIELD VARCHAR(30) NULL, - TIMESTAMP_FIELD TIMESTAMP NULL, - PRIMARY KEY (A_ID) -) -GO - -//// CHANGE name=emptychange -//// CHANGE name=emptychange2 - - -//// CHANGE FK name=chng2 -ALTER TABLE TABLE_A ADD FOREIGN KEY (B_ID) REFERENCES TABLE_B(B_ID) -GO -//// CHANGE name=chng3 -ALTER TABLE TABLE_A ADD COLUMN C_ID INT NULL -GO -//// CHANGE name=extra1 -ALTER TABLE TABLE_A ADD COLUMN EXTRA1 INT NULL -GO -//// CHANGE name=extra2 -ALTER TABLE TABLE_A ADD COLUMN EXTRA2 INT NULL -GO -//// CHANGE name=extra3 -ALTER TABLE TABLE_A ADD COLUMN EXTRA3 INT NULL -GO -//// CHANGE name=extra4 -ALTER TABLE TABLE_A ADD COLUMN EXTRA4 INT NULL -GO +//// CHANGE name=chng1 +CREATE TABLE TABLE_A ( + A_ID INT NOT NULL, + B_ID INT NOT NULL, + STRING_FIELD VARCHAR(30) NULL, + TIMESTAMP_FIELD TIMESTAMP NULL, + PRIMARY KEY (A_ID) +) WITHOUT OIDS +GO + +//// CHANGE name=emptychange +//// CHANGE name=emptychange2 + + +//// CHANGE FK name=chng2 +ALTER TABLE TABLE_A ADD FOREIGN KEY (B_ID) REFERENCES TABLE_B(B_ID) +GO +//// CHANGE name=chng3 +ALTER TABLE TABLE_A ADD COLUMN C_ID INT NULL +GO +//// CHANGE name=extra1 +ALTER TABLE TABLE_A ADD COLUMN EXTRA1 INT NULL +GO +//// CHANGE name=extra2 +ALTER TABLE TABLE_A ADD COLUMN EXTRA2 INT NULL +GO +//// CHANGE name=extra3 +ALTER TABLE TABLE_A ADD COLUMN EXTRA3 INT NULL +GO +//// CHANGE name=extra4 +ALTER TABLE TABLE_A ADD COLUMN EXTRA4 INT NULL +GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_B.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_B.ddl index cff127c4..81b93691 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_B.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_B.ddl @@ -1,5 +1,5 @@ -//// CHANGE name=chng1 -CREATE TABLE TABLE_B ( - B_ID INT NOT NULL, - PRIMARY KEY (B_ID) -) +//// CHANGE name=chng1 +CREATE TABLE TABLE_B ( + B_ID INT NOT NULL, + PRIMARY KEY (B_ID) +) WITHOUT OIDS diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_SPECIAL_COL.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_SPECIAL_COL.ddl index 3114fe83..71698aea 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_SPECIAL_COL.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TABLE_SPECIAL_COL.ddl @@ -3,5 +3,5 @@ CREATE TABLE TABLE_SPECIAL_COL ( UUID_PK UUID NOT NULL, STR1 VARCHAR(30) NULL, PRIMARY KEY (UUID_PK) -) +) WITHOUT OIDS GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TAB_WITH_SEQ.ddl b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TAB_WITH_SEQ.ddl index c6e7ed25..24889b18 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TAB_WITH_SEQ.ddl +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/table/TAB_WITH_SEQ.ddl @@ -1,8 +1,8 @@ -//// METADATA excludePlatforms=REDSHIFT -//// CHANGE name=chng1 -CREATE TABLE TAB_WITH_SEQ ( - ID int4 NOT NULL DEFAULT nextval('MYSEQ1'::regclass), - FIELD1 INT NULL, - PRIMARY KEY (ID) -) -GO +//// METADATA excludePlatforms=REDSHIFT +//// CHANGE name=chng1 +CREATE TABLE TAB_WITH_SEQ ( + ID int4 NOT NULL DEFAULT nextval('MYSEQ1'::regclass), + FIELD1 INT NULL, + PRIMARY KEY (ID) +) WITHOUT OIDS +GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/usertype/usertype0.hsql.sql b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/usertype/usertype0.hsql.sql new file mode 100644 index 00000000..93efe056 --- /dev/null +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/usertype/usertype0.hsql.sql @@ -0,0 +1,3 @@ +//// METADATA includePlatforms="HSQL" +CREATE TYPE usertype0 AS VARCHAR(1); +GO diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/usertype/usertype0.sql b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/usertype/usertype0.sql index bfe03d74..bf6ab05b 100644 --- a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/usertype/usertype0.sql +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/schema1/usertype/usertype0.sql @@ -1,3 +1,4 @@ +//// METADATA excludePlatforms="HSQL" CREATE TYPE usertype0 AS ENUM ( '1', '2', diff --git a/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/system-config-inmem.xml b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/system-config-inmem.xml new file mode 100644 index 00000000..2a94b414 --- /dev/null +++ b/obevo-db-impls/obevo-db-postgresql/src/test/resources/platforms/postgresql/example1/step2/system-config-inmem.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/obevo-db/src/main/java/com/gs/obevo/db/apps/reveng/AbstractDdlReveng.java b/obevo-db/src/main/java/com/gs/obevo/db/apps/reveng/AbstractDdlReveng.java index a8ba9f8b..ceacfd39 100644 --- a/obevo-db/src/main/java/com/gs/obevo/db/apps/reveng/AbstractDdlReveng.java +++ b/obevo-db/src/main/java/com/gs/obevo/db/apps/reveng/AbstractDdlReveng.java @@ -177,7 +177,7 @@ public void reveng(AquaRevengArgs args) { System.out.println("***********"); System.out.println(); System.out.println("Once those steps are done, rerun the reverse-engineering command you just ran, but add the following argument based on the value passed in above the argument:"); - System.out.println(" -inputPath " + ObjectUtils.defaultIfNull(args.getOutputPath(), "")); + System.out.println(" -inputPath " + interimDir.getAbsolutePath()); System.out.println(); System.out.println("If you need more information on the vendor reverse engineer process, see the doc: https://goldmansachs.github.io/obevo/reverse-engineer-dbmstools.html"); } diff --git a/obevo-db/src/main/java/com/gs/obevo/db/impl/platforms/sqltranslator/PostColumnSqlTranslator.java b/obevo-db/src/main/java/com/gs/obevo/db/impl/platforms/sqltranslator/PostColumnSqlTranslator.java index 9e50df7c..9ecbd896 100644 --- a/obevo-db/src/main/java/com/gs/obevo/db/impl/platforms/sqltranslator/PostColumnSqlTranslator.java +++ b/obevo-db/src/main/java/com/gs/obevo/db/impl/platforms/sqltranslator/PostColumnSqlTranslator.java @@ -1,23 +1,23 @@ -/** - * Copyright 2017 Goldman Sachs. - * 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 - * - * http://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 com.gs.obevo.db.impl.platforms.sqltranslator; - -import com.gs.obevo.db.sqlparser.syntaxparser.CreateTable; -import com.gs.obevo.db.sqlparser.syntaxparser.CreateTableColumn; - -public interface PostColumnSqlTranslator { - String handlePostColumnText(String sql, CreateTableColumn column, CreateTable table); -} +/** + * Copyright 2017 Goldman Sachs. + * 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 + * + * http://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 com.gs.obevo.db.impl.platforms.sqltranslator; + +import com.gs.obevo.db.sqlparser.syntaxparser.CreateTable; +import com.gs.obevo.db.sqlparser.syntaxparser.CreateTableColumn; + +public interface PostColumnSqlTranslator { + String handlePostColumnText(String postColumnText, CreateTableColumn column, CreateTable table); +} diff --git a/obevo-db/src/main/jjtree/sqlInMemTranslate.jjt b/obevo-db/src/main/jjtree/sqlInMemTranslate.jjt index 5fd2b427..2841294b 100644 --- a/obevo-db/src/main/jjtree/sqlInMemTranslate.jjt +++ b/obevo-db/src/main/jjtree/sqlInMemTranslate.jjt @@ -157,7 +157,7 @@ TOKEN : TOKEN : { - < IDENTIFIER: (||||||)+ > + < IDENTIFIER: (|||||||)+ > | < #LETTER: [ @@ -211,6 +211,7 @@ TOKEN : | < DOLLAR: "$" > | < DOT: "." > | < POUND: "#" > +| < COLON: ":" > } diff --git a/obevo-utils/obevo-db-unittest-util/src/main/java/com/gs/obevo/db/unittest/UnitTestDbBuilder.java b/obevo-utils/obevo-db-unittest-util/src/main/java/com/gs/obevo/db/unittest/UnitTestDbBuilder.java index 0b8aa94b..8fdb046e 100644 --- a/obevo-utils/obevo-db-unittest-util/src/main/java/com/gs/obevo/db/unittest/UnitTestDbBuilder.java +++ b/obevo-utils/obevo-db-unittest-util/src/main/java/com/gs/obevo/db/unittest/UnitTestDbBuilder.java @@ -1,288 +1,295 @@ -/** - * Copyright 2017 Goldman Sachs. - * 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 - * - * http://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 com.gs.obevo.db.unittest; - -import java.io.File; -import java.util.Set; - -import com.gs.obevo.api.appdata.ChangeKey; -import com.gs.obevo.api.platform.ChangeType; -import com.gs.obevo.api.platform.MainDeployerArgs; -import com.gs.obevo.db.api.appdata.DbEnvironment; -import com.gs.obevo.db.api.appdata.Permission; -import com.gs.obevo.db.api.factory.DbEnvironmentFactory; -import com.gs.obevo.db.api.platform.DbDeployerAppContext; -import com.gs.obevo.db.api.platform.DbPlatform; -import com.gs.obevo.impl.changepredicate.ChangeKeyPredicateBuilder; -import com.gs.obevo.util.inputreader.Credential; -import org.apache.commons.lang3.Validate; -import org.eclipse.collections.api.block.predicate.Predicate; -import org.eclipse.collections.api.list.MutableList; -import org.eclipse.collections.api.map.MutableMap; -import org.eclipse.collections.api.set.ImmutableSet; -import org.eclipse.collections.impl.block.factory.Predicates; -import org.eclipse.collections.impl.factory.Lists; -import org.eclipse.collections.impl.factory.Maps; -import org.eclipse.collections.impl.factory.Sets; - -/** - * Helper class for building unit test db environments and contexts, i.e. to not have to remember details for each unit - * test db type and to easily switch between unit test DBMS's if needed - * - * Ultimately, this will delegate to Environment.getAppContextBuilder() for building the context. This class will mainly - * leverage a client's existing DbEnvironment setup and tweak values accordingly - * - * If an existing environment is referenced, a copy of that DbEnvironment will be made by this class so that any changes - * to that object will not impact anything existing - */ -public class UnitTestDbBuilder { - public static UnitTestDbBuilder newBuilder() { - return new UnitTestDbBuilder(); - } - - /** - * Caching the contexts created so that subsequent operations on this can go quickly (i.e. avoiding the costs of - * reading the contents from the file system). - */ - private static final MutableMap cachedContexts = Maps.mutable.empty(); - - private String sourcePath; - private String envName; - private String referenceEnvName; - private DbPlatform dbPlatform; - private String dbServer = "test"; - private ImmutableSet tables; - private ImmutableSet views; - private boolean persistToFile = false; - private boolean grantsDisabled = true; // disabling grants by default for unit tests as in practice, most teams - private File workDir = new File("./target/unitdb"); - private Credential credential = new Credential("sa", ""); - - /** - * (Required) path to read environment metadata from - */ - public UnitTestDbBuilder setSourcePath(String sourcePath) { - this.sourcePath = sourcePath; - return this; - } - - /** - * Name to give the environment created during this builder - * - * If not specified, will use the name and environment specified by the referenceEnvName parameter - */ - public UnitTestDbBuilder setEnvName(String envName) { - this.envName = envName; - return this; - } - - /** - * Environment to use as a model for the unit test db environment to create - * - * If not specified, then one of the environments read from the source path will be picked arbitrarily. The envName - * parameter must then be specified to give this unit test db environment a known name - */ - public UnitTestDbBuilder setReferenceEnvName(String referenceEnvName) { - this.referenceEnvName = referenceEnvName; - return this; - } - - /** - * dbPlatform to use for the new unit test db - * - * If not specified, will default to the dbPlatform of the reference environment - */ - public UnitTestDbBuilder setDbPlatform(DbPlatform dbPlatform) { - this.dbPlatform = dbPlatform; - return this; - } - - /** - * Name of the in-memory db to be created to be used when creating the URL, e.g. jdbc:h2:mem:<dbServer>:etc. - * This is a convenience for clients to not have to remember the URL convention. The resolved URL can be retrieved - * from the DbEnvironment instance - * - * If not specified, will default to "test" - */ - public UnitTestDbBuilder setDbServer(String dbServer) { - this.dbServer = dbServer; - return this; - } - - /** - * Specify this to restrict the tables deployed to just the ones provided. If not specified, all tables will be deployed. - * - * @deprecated Specify these fields to remove in the {@link DbDeployerAppContext#deploy(MainDeployerArgs)} arguments itself. - */ - @Deprecated - public UnitTestDbBuilder setTables(Set tables) { - this.tables = Sets.immutable.withAll(tables); - return this; - } - - /** - * Specify this to restrict the views deployed to just the ones provided. If not specified, all views will be deployed. - * - * @deprecated Specify these fields to remove in the {@link DbDeployerAppContext#deploy(MainDeployerArgs)} arguments itself. - */ - @Deprecated - public UnitTestDbBuilder setViews(Set views) { - this.views = Sets.immutable.withAll(views); - return this; - } - - /** - * If true, will generate the file-persistent URL for the in-memory database. If false, goes w/ the in-memory URL - * - * Defaults to false (in-memory) - */ - public UnitTestDbBuilder setPersistToFile(boolean persistToFile) { - this.persistToFile = persistToFile; - return this; - } - - private boolean isPersistToFile() { - // We support this system property here to facilitate easy debugging for - // unit tests (i.e. if we don't want to change the code accidentally when running/debugging) - // But we can still set this programatically anyway - if (System.getProperty("debugDbUnit") == null) { - return this.persistToFile; - } else { - return "true".equalsIgnoreCase(System.getProperty("debugDbUnit")); - } - } - - /** - * @deprecated Clients should move off this. Leverage the groups and users sections in your DbEnvironment configuration to have the grants created - */ - @Deprecated - public UnitTestDbBuilder setGrantsDisabled(boolean grantsDisabled) { - this.grantsDisabled = grantsDisabled; - return this; - } - - /** - * The workDir to use for any temporary files used for the db deployment - * - * If not specified, defaults to "./target/unitdb" (i.e. relative to your working directory) - */ - public UnitTestDbBuilder setWorkDir(File workDir) { - this.workDir = workDir; - return this; - } - - /** - * (optional) credential defaults to username==sa and password==<blank>, per the default convention of h2/hsql - */ - public UnitTestDbBuilder setCredential(Credential credential) { - this.credential = credential; - return this; - } - - private void validateBuilder() { - if (envName == null && referenceEnvName == null) { - throw new IllegalArgumentException("One of envName or referenceEnvName must be populated"); - } - Validate.notNull(sourcePath); - Validate.notNull(credential); - } - - public DbDeployerAppContext buildContext() { - validateBuilder(); - - String instanceLookupKey = instanceLookupKey(); - - DbDeployerAppContext baseContext = cachedContexts.get(instanceLookupKey); - - if (baseContext == null) { - baseContext = buildContextUncached(); - cachedContexts.put(instanceLookupKey, baseContext); - } - - // set the arguments that should be used as defined in this builder class, e.g. for limiting by specific tables - return new UnitTestDbDeployerAppContext(baseContext, getMainDeployerArgs()); - } - - /** - * Builds the deployer context. See the class Javadoc for more information - */ - private DbDeployerAppContext buildContextUncached() { - validateBuilder(); - - String[] envsToRequest = this.referenceEnvName != null ? new String[] { this.referenceEnvName } : new String[0]; - DbEnvironment referenceEnv = DbEnvironmentFactory.getInstance().readFromSourcePath(this.sourcePath, envsToRequest) - .getFirst(); - - DbEnvironment env = referenceEnv.createCopy(); - - if (this.envName != null) { - env.setName(this.envName); - } - - env.setDisableAuditTracking(true); - env.setPersistToFile(this.isPersistToFile()); - - if (this.dbPlatform != null) { - env.setPlatform(this.dbPlatform); - } - - if (this.dbServer != null) { - env.setDbServer(this.dbServer); - } - - if (this.grantsDisabled) { - env.setPermissions(Lists.immutable.empty()); - } - - env.setDefaultUserId(credential.getUsername()); - env.setDefaultPassword(credential.getPassword()); - - return env.getAppContextBuilder() - .setWorkDir(workDir) - .build(); - } - - private MainDeployerArgs getMainDeployerArgs() { - MainDeployerArgs args = new MainDeployerArgs(); - - if (this.tables != null || this.views != null) { - MutableList> predicates = Lists.mutable.empty(); - if (this.tables != null) { - predicates.add(ChangeKeyPredicateBuilder.newBuilder() - .setChangeTypes(ChangeType.TABLE_STR, ChangeType.FOREIGN_KEY_STR, ChangeType.TRIGGER_INCREMENTAL_OLD_STR, ChangeType.STATICDATA_STR) - .setObjectNames(Sets.immutable.withAll(this.tables)) - .build()); - } - if (this.views != null) { - predicates.add(ChangeKeyPredicateBuilder.newBuilder() - .setChangeTypes(ChangeType.VIEW_STR) - .setObjectNames(Sets.immutable.withAll(this.views)) - .build()); - } - - args.setChangeInclusionPredicate(Predicates.or(predicates)); - } - - args.setAllChangesets(true); // for unit tests, we always want all changes to deploy - return args; - } - - private String instanceLookupKey() { - String envNameToLookup = envName != null ? envName : referenceEnvName; - - return this.sourcePath + ":" + envNameToLookup; - } -} +/** + * Copyright 2017 Goldman Sachs. + * 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 + * + * http://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 com.gs.obevo.db.unittest; + +import java.io.File; +import java.util.Set; + +import com.gs.obevo.api.appdata.ChangeKey; +import com.gs.obevo.api.platform.ChangeType; +import com.gs.obevo.api.platform.MainDeployerArgs; +import com.gs.obevo.db.api.appdata.DbEnvironment; +import com.gs.obevo.db.api.appdata.Permission; +import com.gs.obevo.db.api.factory.DbEnvironmentFactory; +import com.gs.obevo.db.api.platform.DbDeployerAppContext; +import com.gs.obevo.db.api.platform.DbPlatform; +import com.gs.obevo.impl.changepredicate.ChangeKeyPredicateBuilder; +import com.gs.obevo.util.inputreader.Credential; +import org.apache.commons.lang3.Validate; +import org.eclipse.collections.api.block.predicate.Predicate; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.api.map.MutableMap; +import org.eclipse.collections.api.set.ImmutableSet; +import org.eclipse.collections.impl.block.factory.Predicates; +import org.eclipse.collections.impl.factory.Lists; +import org.eclipse.collections.impl.factory.Maps; +import org.eclipse.collections.impl.factory.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Helper class for building unit test db environments and contexts, i.e. to not have to remember details for each unit + * test db type and to easily switch between unit test DBMS's if needed + * + * Ultimately, this will delegate to Environment.getAppContextBuilder() for building the context. This class will mainly + * leverage a client's existing DbEnvironment setup and tweak values accordingly + * + * If an existing environment is referenced, a copy of that DbEnvironment will be made by this class so that any changes + * to that object will not impact anything existing + */ +public class UnitTestDbBuilder { + private static final Logger LOG = LoggerFactory.getLogger(UnitTestDbBuilder.class); + public static UnitTestDbBuilder newBuilder() { + return new UnitTestDbBuilder(); + } + + /** + * Caching the contexts created so that subsequent operations on this can go quickly (i.e. avoiding the costs of + * reading the contents from the file system). + */ + private static final MutableMap cachedContexts = Maps.mutable.empty(); + + private String sourcePath; + private String envName; + private String referenceEnvName; + private DbPlatform dbPlatform; + private String dbServer = "test"; + private ImmutableSet tables; + private ImmutableSet views; + private boolean persistToFile = false; + private boolean grantsDisabled = true; // disabling grants by default for unit tests as in practice, most teams + private File workDir = new File("./target/unitdb"); + private Credential credential = new Credential("sa", ""); + + /** + * (Required) path to read environment metadata from + */ + public UnitTestDbBuilder setSourcePath(String sourcePath) { + this.sourcePath = sourcePath; + return this; + } + + /** + * Name to give the environment created during this builder + * + * If not specified, will use the name and environment specified by the referenceEnvName parameter + */ + public UnitTestDbBuilder setEnvName(String envName) { + this.envName = envName; + return this; + } + + /** + * Environment to use as a model for the unit test db environment to create + * + * If not specified, then one of the environments read from the source path will be picked arbitrarily. The envName + * parameter must then be specified to give this unit test db environment a known name + */ + public UnitTestDbBuilder setReferenceEnvName(String referenceEnvName) { + this.referenceEnvName = referenceEnvName; + return this; + } + + /** + * dbPlatform to use for the new unit test db + * + * If not specified, will default to the dbPlatform of the reference environment + */ + public UnitTestDbBuilder setDbPlatform(DbPlatform dbPlatform) { + this.dbPlatform = dbPlatform; + return this; + } + + /** + * Name of the in-memory db to be created to be used when creating the URL, e.g. jdbc:h2:mem:<dbServer>:etc. + * This is a convenience for clients to not have to remember the URL convention. The resolved URL can be retrieved + * from the DbEnvironment instance + * + * If not specified, will default to "test" + */ + public UnitTestDbBuilder setDbServer(String dbServer) { + this.dbServer = dbServer; + return this; + } + + /** + * Specify this to restrict the tables deployed to just the ones provided. If not specified, all tables will be deployed. + * + * @deprecated Specify these fields to remove in the {@link DbDeployerAppContext#deploy(MainDeployerArgs)} arguments itself. + */ + @Deprecated + public UnitTestDbBuilder setTables(Set tables) { + this.tables = Sets.immutable.withAll(tables); + return this; + } + + /** + * Specify this to restrict the views deployed to just the ones provided. If not specified, all views will be deployed. + * + * @deprecated Specify these fields to remove in the {@link DbDeployerAppContext#deploy(MainDeployerArgs)} arguments itself. + */ + @Deprecated + public UnitTestDbBuilder setViews(Set views) { + this.views = Sets.immutable.withAll(views); + return this; + } + + /** + * If true, will generate the file-persistent URL for the in-memory database. If false, goes w/ the in-memory URL + * + * Defaults to false (in-memory) + */ + public UnitTestDbBuilder setPersistToFile(boolean persistToFile) { + this.persistToFile = persistToFile; + return this; + } + + private boolean isPersistToFile() { + // We support this system property here to facilitate easy debugging for + // unit tests (i.e. if we don't want to change the code accidentally when running/debugging) + // But we can still set this programatically anyway + if (System.getProperty("debugDbUnit") == null) { + return this.persistToFile; + } else { + return "true".equalsIgnoreCase(System.getProperty("debugDbUnit")); + } + } + + /** + * @deprecated Clients should move off this. Leverage the groups and users sections in your DbEnvironment configuration to have the grants created + */ + @Deprecated + public UnitTestDbBuilder setGrantsDisabled(boolean grantsDisabled) { + this.grantsDisabled = grantsDisabled; + return this; + } + + /** + * The workDir to use for any temporary files used for the db deployment + * + * If not specified, defaults to "./target/unitdb" (i.e. relative to your working directory) + */ + public UnitTestDbBuilder setWorkDir(File workDir) { + this.workDir = workDir; + return this; + } + + /** + * (optional) credential defaults to username==sa and password==<blank>, per the default convention of h2/hsql + */ + public UnitTestDbBuilder setCredential(Credential credential) { + this.credential = credential; + return this; + } + + private void validateBuilder() { + if (envName == null && referenceEnvName == null) { + throw new IllegalArgumentException("One of envName or referenceEnvName must be populated"); + } + Validate.notNull(sourcePath); + Validate.notNull(credential); + } + + public DbDeployerAppContext buildContext() { + validateBuilder(); + + String instanceLookupKey = instanceLookupKey(); + + DbDeployerAppContext baseContext = cachedContexts.get(instanceLookupKey); + + if (baseContext == null) { + baseContext = buildContextUncached(); + cachedContexts.put(instanceLookupKey, baseContext); + } + + // set the arguments that should be used as defined in this builder class, e.g. for limiting by specific tables + return new UnitTestDbDeployerAppContext(baseContext, getMainDeployerArgs()); + } + + /** + * Builds the deployer context. See the class Javadoc for more information + */ + private DbDeployerAppContext buildContextUncached() { + validateBuilder(); + + String[] envsToRequest = this.referenceEnvName != null ? new String[] { this.referenceEnvName } : new String[0]; + DbEnvironment referenceEnv = DbEnvironmentFactory.getInstance().readFromSourcePath(this.sourcePath, envsToRequest) + .getFirst(); + + DbEnvironment env = referenceEnv.createCopy(); + + if (this.envName != null) { + env.setName(this.envName); + } + + env.setDisableAuditTracking(true); + env.setPersistToFile(this.isPersistToFile()); + + if (this.dbPlatform != null) { + env.setPlatform(this.dbPlatform); + } + + if (this.dbServer != null) { + if (env.getJdbcUrl() != null) { + LOG.debug("Unsetting existing JDBC URL value, as we can rely on the in-memory DB value to be set here"); + env.setJdbcUrl(null); + } + env.setDbServer(this.dbServer); + } + + if (this.grantsDisabled) { + env.setPermissions(Lists.immutable.empty()); + } + + env.setDefaultUserId(credential.getUsername()); + env.setDefaultPassword(credential.getPassword()); + + return env.getAppContextBuilder() + .setWorkDir(workDir) + .build(); + } + + private MainDeployerArgs getMainDeployerArgs() { + MainDeployerArgs args = new MainDeployerArgs(); + + if (this.tables != null || this.views != null) { + MutableList> predicates = Lists.mutable.empty(); + if (this.tables != null) { + predicates.add(ChangeKeyPredicateBuilder.newBuilder() + .setChangeTypes(ChangeType.TABLE_STR, ChangeType.FOREIGN_KEY_STR, ChangeType.TRIGGER_INCREMENTAL_OLD_STR, ChangeType.STATICDATA_STR) + .setObjectNames(Sets.immutable.withAll(this.tables)) + .build()); + } + if (this.views != null) { + predicates.add(ChangeKeyPredicateBuilder.newBuilder() + .setChangeTypes(ChangeType.VIEW_STR) + .setObjectNames(Sets.immutable.withAll(this.views)) + .build()); + } + + args.setChangeInclusionPredicate(Predicates.or(predicates)); + } + + args.setAllChangesets(true); // for unit tests, we always want all changes to deploy + return args; + } + + private String instanceLookupKey() { + String envNameToLookup = envName != null ? envName : referenceEnvName; + + return this.sourcePath + ":" + envNameToLookup; + } +}