Merge remote-tracking branch 'remotes/origin/master' into add-pid-to-created-resource
This commit is contained in:
commit
a68addf89a
|
@ -17,12 +17,12 @@
|
|||
<th:block th:case="'DSTU1'">
|
||||
<th:block th:if="${not resource.name.textElement.empty}" th:text="${resource.name.textElement.value}"/>
|
||||
<th:block th:if=" ${resource.name.textElement.empty} and ${not resource.name.coding[0].displayElement.empty}" th:text="${resource.name.coding[0].display}"/>
|
||||
<th:block th:if= "${resource.name.textElement.empty} and ${resource.name.coding[0].displayElement.empty}" th:text="Untitled Diagnostic Report"/>
|
||||
<th:block th:if= "${resource.name.textElement.empty} and ${resource.name.coding[0].displayElement.empty}" th:text="'Untitled Diagnostic Report'"/>
|
||||
</th:block>
|
||||
<th:block th:case="*">
|
||||
<th:block th:if="${not resource.code.textElement.empty} or ${resource.code.coding.empty}" th:text="${resource.code.textElement.value}"/>
|
||||
<th:block th:if="${not resource.code.coding.empty} and ${resource.code.textElement.empty} and ${not resource.code.coding[0].displayElement.empty}" th:text="${resource.code.coding[0].display}"/>
|
||||
<th:block th:if="${not resource.code.coding.empty} and ${resource.code.textElement.empty} and ${resource.code.coding[0].displayElement.empty}" th:text="Untitled Diagnostic Report"/>
|
||||
<th:block th:if="${not resource.code.coding.empty} and ${resource.code.textElement.empty} and ${resource.code.coding[0].displayElement.empty}" th:text="'Untitled Diagnostic Report'"/>
|
||||
</th:block>
|
||||
</th:block>
|
||||
<!--/*--> Complete Blood Count <!--*/-->
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.util;
|
|||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import com.google.common.reflect.ClassPath.ClassInfo;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -38,10 +39,7 @@ import java.io.InputStream;
|
|||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Ascii.toUpperCase;
|
||||
|
@ -145,6 +143,13 @@ public class TestUtil {
|
|||
private static void scan(AnnotatedElement theAnnotatedElement, Set<String> theNames, boolean theIsSuperClass) {
|
||||
Table table = theAnnotatedElement.getAnnotation(Table.class);
|
||||
if (table != null) {
|
||||
|
||||
// Banned name because we already used it once
|
||||
ArrayList<String> bannedNames = Lists.newArrayList("CDR_USER_2FA", "TRM_VALUESET_CODE");
|
||||
Validate.isTrue(!bannedNames.contains(table.name().toUpperCase()));
|
||||
|
||||
Validate.isTrue(table.name().toUpperCase().equals(table.name()));
|
||||
|
||||
assertNotADuplicateName(table.name(), theNames);
|
||||
for (UniqueConstraint nextConstraint : table.uniqueConstraints()) {
|
||||
assertNotADuplicateName(nextConstraint.name(), theNames);
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -344,6 +345,7 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
|
|||
assertEquals(2, search.getResources(0, 2).size());
|
||||
|
||||
runInTransaction(() -> {
|
||||
await().until(()->mySearchResultDao.count() == 2);
|
||||
ourLog.info("Search results: {}", mySearchResultDao.findAll().toString());
|
||||
assertEquals(mySearchResultDao.findAll().toString(), 2, mySearchResultDao.count());
|
||||
});
|
||||
|
|
|
@ -79,9 +79,6 @@
|
|||
|
||||
<build>
|
||||
|
||||
<!-- Tells Maven to name the generated WAR file as hapi-fhir-jpaserver-example.war -->
|
||||
<finalName>hapi-fhir-jpaserver-example</finalName>
|
||||
|
||||
<!-- The following is not required for the application to build, but allows you to test it by issuing "mvn jetty:run" from the command line. -->
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
|
|
|
@ -41,10 +41,7 @@ import org.springframework.jdbc.core.ColumnMapRowMapper;
|
|||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.thymeleaf.util.StringUtils.toUpperCase;
|
||||
|
||||
|
@ -56,25 +53,37 @@ public class JdbcUtils {
|
|||
*/
|
||||
public static Set<String> getIndexNames(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName) throws SQLException {
|
||||
|
||||
if (!getTableNames(theConnectionProperties).contains(theTableName)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
DataSource dataSource = Objects.requireNonNull(theConnectionProperties.getDataSource());
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
return theConnectionProperties.getTxTemplate().execute(t -> {
|
||||
DatabaseMetaData metadata;
|
||||
try {
|
||||
metadata = connection.getMetaData();
|
||||
ResultSet indexes = metadata.getIndexInfo(connection.getCatalog(), connection.getSchema(), massageIdentifier(metadata, theTableName), false, true);
|
||||
|
||||
ResultSet indexes = metadata.getIndexInfo(connection.getCatalog(), connection.getSchema(), massageIdentifier(metadata, theTableName), false, false);
|
||||
Set<String> indexNames = new HashSet<>();
|
||||
while (indexes.next()) {
|
||||
|
||||
ourLog.debug("*** Next index: {}", new ColumnMapRowMapper().mapRow(indexes, 0));
|
||||
|
||||
String indexName = indexes.getString("INDEX_NAME");
|
||||
indexName = toUpperCase(indexName, Locale.US);
|
||||
indexNames.add(indexName);
|
||||
}
|
||||
|
||||
indexes = metadata.getIndexInfo(connection.getCatalog(), connection.getSchema(), massageIdentifier(metadata, theTableName), true, false);
|
||||
while (indexes.next()) {
|
||||
ourLog.debug("*** Next index: {}", new ColumnMapRowMapper().mapRow(indexes, 0));
|
||||
String indexName = indexes.getString("INDEX_NAME");
|
||||
indexName = toUpperCase(indexName, Locale.US);
|
||||
indexNames.add(indexName);
|
||||
}
|
||||
|
||||
indexNames.removeIf(i -> i == null);
|
||||
return indexNames;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,8 @@ public class AddIndexTask extends BaseTableTask<AddIndexTask> {
|
|||
return;
|
||||
}
|
||||
|
||||
ourLog.info("Going to add a {} index named {} on table {} for columns {}", (myUnique ? "UNIQUE" : "NON-UNIQUE"), myIndexName, getTableName(), myColumns);
|
||||
|
||||
String unique = myUnique ? "unique " : "";
|
||||
String columns = String.join(", ", myColumns);
|
||||
String sql = "create " + unique + "index " + myIndexName + " on " + getTableName() + "(" + columns + ")";
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.migrate.taskdef;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -40,9 +41,16 @@ public class DropColumnTask extends BaseTableColumnTask<DropColumnTask> {
|
|||
return;
|
||||
}
|
||||
|
||||
String sql = "alter table " + getTableName() + " drop column " + getColumnName();
|
||||
String tableName = getTableName();
|
||||
String columnName = getColumnName();
|
||||
String sql = createSql(tableName, columnName);
|
||||
ourLog.info("Dropping column {} on table {}", getColumnName(), getTableName());
|
||||
executeSql(getTableName(), sql);
|
||||
}
|
||||
|
||||
@Language("SQL")
|
||||
static String createSql(String theTableName, String theColumnName) {
|
||||
return "alter table " + theTableName + " drop column " + theColumnName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,11 +20,13 @@ package ca.uhn.fhir.jpa.migrate.taskdef;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -56,45 +58,56 @@ public class DropIndexTask extends BaseTableTask<DropIndexTask> {
|
|||
String uniquenessString = isUnique ? "unique" : "non-unique";
|
||||
ourLog.info("Dropping {} index {} on table {}", uniquenessString, myIndexName, getTableName());
|
||||
|
||||
String sql = createDropIndexSql(getConnectionProperties(), getTableName(), myIndexName, getDriverType());
|
||||
executeSql(getTableName(), sql);
|
||||
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
static String createDropIndexSql(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName, String theIndexName, DriverTypeEnum theDriverType) throws SQLException {
|
||||
Validate.notBlank(theIndexName, "theIndexName must not be blank");
|
||||
Validate.notBlank(theTableName, "theTableName must not be blank");
|
||||
|
||||
boolean isUnique = JdbcUtils.isIndexUnique(theConnectionProperties, theTableName, theIndexName);
|
||||
|
||||
String sql = null;
|
||||
|
||||
if (isUnique) {
|
||||
// Drop constraint
|
||||
switch (getDriverType()) {
|
||||
switch (theDriverType) {
|
||||
case MYSQL_5_7:
|
||||
case MARIADB_10_1:
|
||||
sql = "alter table " + getTableName() + " drop index " + myIndexName;
|
||||
sql = "alter table " + theTableName + " drop index " + theIndexName;
|
||||
break;
|
||||
case H2_EMBEDDED:
|
||||
case DERBY_EMBEDDED:
|
||||
sql = "drop index " + myIndexName;
|
||||
sql = "drop index " + theIndexName;
|
||||
break;
|
||||
case POSTGRES_9_4:
|
||||
case ORACLE_12C:
|
||||
case MSSQL_2012:
|
||||
sql = "alter table " + getTableName() + " drop constraint " + myIndexName;
|
||||
sql = "alter table " + theTableName + " drop constraint " + theIndexName;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Drop index
|
||||
switch (getDriverType()) {
|
||||
switch (theDriverType) {
|
||||
case MYSQL_5_7:
|
||||
case MARIADB_10_1:
|
||||
sql = "alter table " + getTableName() + " drop index " + myIndexName;
|
||||
sql = "alter table " + theTableName + " drop index " + theIndexName;
|
||||
break;
|
||||
case POSTGRES_9_4:
|
||||
case DERBY_EMBEDDED:
|
||||
case H2_EMBEDDED:
|
||||
case ORACLE_12C:
|
||||
sql = "drop index " + myIndexName;
|
||||
sql = "drop index " + theIndexName;
|
||||
break;
|
||||
case MSSQL_2012:
|
||||
sql = "drop index " + getTableName() + "." + myIndexName;
|
||||
sql = "drop index " + theTableName + "." + theIndexName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
executeSql(getTableName(), sql);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server - Migration
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
||||
public class DropTableTask extends BaseTableTask<DropTableTask> {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(DropTableTask.class);
|
||||
|
||||
@Override
|
||||
public void execute() throws SQLException {
|
||||
Set<String> tableNames = JdbcUtils.getTableNames(getConnectionProperties());
|
||||
if (!tableNames.contains(getTableName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> indexNames = JdbcUtils.getIndexNames(getConnectionProperties(), getTableName());
|
||||
for (String nextIndex : indexNames) {
|
||||
String sql = DropIndexTask.createDropIndexSql(getConnectionProperties(), getTableName(), nextIndex, getDriverType());
|
||||
ourLog.info("Dropping index {} on table {} in preparation for table delete", nextIndex, getTableName());
|
||||
executeSql(getTableName(), sql);
|
||||
}
|
||||
|
||||
ourLog.info("Dropping table: {}", getTableName());
|
||||
|
||||
String sql = "DROP TABLE " + getTableName();
|
||||
executeSql(getTableName(), sql);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -24,6 +24,8 @@ import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
@ -34,6 +36,11 @@ public class RenameColumnTask extends BaseTableTask<RenameColumnTask> {
|
|||
private String myOldName;
|
||||
private String myNewName;
|
||||
private boolean myAllowNeitherColumnToExist;
|
||||
private boolean myDeleteTargetColumnFirstIfBothExist;
|
||||
|
||||
public void setDeleteTargetColumnFirstIfBothExist(boolean theDeleteTargetColumnFirstIfBothExist) {
|
||||
myDeleteTargetColumnFirstIfBothExist = theDeleteTargetColumnFirstIfBothExist;
|
||||
}
|
||||
|
||||
public void setOldName(String theOldName) {
|
||||
Validate.notBlank(theOldName);
|
||||
|
@ -51,15 +58,30 @@ public class RenameColumnTask extends BaseTableTask<RenameColumnTask> {
|
|||
boolean haveOldName = columnNames.contains(myOldName.toUpperCase());
|
||||
boolean haveNewName = columnNames.contains(myNewName.toUpperCase());
|
||||
if (haveOldName && haveNewName) {
|
||||
throw new SQLException("Can not rename " + getTableName() + "." + myOldName + " to " + myNewName + " because both columns exist!");
|
||||
}
|
||||
if (!haveOldName && !haveNewName) {
|
||||
if (myDeleteTargetColumnFirstIfBothExist) {
|
||||
|
||||
Integer rowsWithData = getConnectionProperties().getTxTemplate().execute(t -> {
|
||||
String sql = "SELECT * FROM " + getTableName() + " WHERE " + myNewName + " IS NOT NULL";
|
||||
JdbcTemplate jdbcTemplate = getConnectionProperties().newJdbcTemplate();
|
||||
jdbcTemplate.setMaxRows(1);
|
||||
return jdbcTemplate.query(sql, new ColumnMapRowMapper()).size();
|
||||
});
|
||||
if (rowsWithData > 0) {
|
||||
throw new SQLException("Can not rename " + getTableName() + "." + myOldName + " to " + myNewName + " because both columns exist and data exists in " + myNewName);
|
||||
}
|
||||
|
||||
ourLog.info("Table {} has columns {} and {} - Going to drop {} before renaming", getTableName(), myOldName, myNewName, myNewName);
|
||||
String sql = DropColumnTask.createSql(getTableName(), myNewName);
|
||||
executeSql(getTableName(), sql);
|
||||
} else {
|
||||
throw new SQLException("Can not rename " + getTableName() + "." + myOldName + " to " + myNewName + " because both columns exist!");
|
||||
}
|
||||
} else if (!haveOldName && !haveNewName) {
|
||||
if (isAllowNeitherColumnToExist()) {
|
||||
return;
|
||||
}
|
||||
throw new SQLException("Can not rename " + getTableName() + "." + myOldName + " to " + myNewName + " because neither column exists!");
|
||||
}
|
||||
if (haveNewName) {
|
||||
} else if (haveNewName) {
|
||||
ourLog.info("Column {} already exists on table {} - No action performed", myNewName, getTableName());
|
||||
return;
|
||||
}
|
||||
|
@ -94,11 +116,11 @@ public class RenameColumnTask extends BaseTableTask<RenameColumnTask> {
|
|||
|
||||
}
|
||||
|
||||
public void setAllowNeitherColumnToExist(boolean theAllowNeitherColumnToExist) {
|
||||
myAllowNeitherColumnToExist = theAllowNeitherColumnToExist;
|
||||
}
|
||||
|
||||
public boolean isAllowNeitherColumnToExist() {
|
||||
return myAllowNeitherColumnToExist;
|
||||
}
|
||||
|
||||
public void setAllowNeitherColumnToExist(boolean theAllowNeitherColumnToExist) {
|
||||
myAllowNeitherColumnToExist = theAllowNeitherColumnToExist;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,32 +63,31 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
protected void init400() {
|
||||
Builder version = forVersion(VersionEnum.V4_0_0);
|
||||
|
||||
// Interim builds used this name
|
||||
version.onTable("TRM_VALUESET_CODE").dropThisTable();
|
||||
|
||||
version.onTable("TRM_CONCEPT_MAP_GROUP")
|
||||
.renameColumn("myConceptMapUrl", "CONCEPT_MAP_URL")
|
||||
.renameColumn("mySourceValueSet", "SOURCE_VS")
|
||||
.renameColumn("myTargetValueSet", "TARGET_VS");
|
||||
.renameColumn("myConceptMapUrl", "CONCEPT_MAP_URL", false, true)
|
||||
.renameColumn("mySourceValueSet", "SOURCE_VS", false, true)
|
||||
.renameColumn("myTargetValueSet", "TARGET_VS", false, true);
|
||||
|
||||
version.onTable("TRM_CONCEPT_MAP_GRP_ELEMENT")
|
||||
.renameColumn("myConceptMapUrl", "CONCEPT_MAP_URL")
|
||||
.renameColumn("mySystem", "SYSTEM_URL")
|
||||
.renameColumn("mySystemVersion", "SYSTEM_VERSION")
|
||||
.renameColumn("myValueSet", "VALUESET_URL");
|
||||
.renameColumn("myConceptMapUrl", "CONCEPT_MAP_URL", false, true)
|
||||
.renameColumn("mySystem", "SYSTEM_URL", false, true)
|
||||
.renameColumn("mySystemVersion", "SYSTEM_VERSION", false, true)
|
||||
.renameColumn("myValueSet", "VALUESET_URL", false, true);
|
||||
|
||||
version.onTable("TRM_CONCEPT_MAP_GRP_ELM_TGT")
|
||||
.renameColumn("myConceptMapUrl", "CONCEPT_MAP_URL")
|
||||
.renameColumn("mySystem", "SYSTEM_URL")
|
||||
.renameColumn("mySystemVersion", "SYSTEM_VERSION")
|
||||
.renameColumn("myValueSet", "VALUESET_URL");
|
||||
.renameColumn("myConceptMapUrl", "CONCEPT_MAP_URL", false, true)
|
||||
.renameColumn("mySystem", "SYSTEM_URL", false, true)
|
||||
.renameColumn("mySystemVersion", "SYSTEM_VERSION", false, true)
|
||||
.renameColumn("myValueSet", "VALUESET_URL", false, true);
|
||||
|
||||
version.onTable("TRM_VALUESET")
|
||||
.renameColumn("NAME", "VSNAME", true);
|
||||
|
||||
version.onTable("TRM_VALUESET_CONCEPT")
|
||||
.renameColumn("CODE", "CODEVAL", true)
|
||||
.renameColumn("SYSTEM", "SYSTEM_URL", true);
|
||||
.renameColumn("NAME", "VSNAME", true, true);
|
||||
|
||||
version.onTable("TRM_CONCEPT")
|
||||
.renameColumn("CODE", "CODEVAL");
|
||||
.renameColumn("CODE", "CODEVAL", false, true);
|
||||
|
||||
// TermValueSet
|
||||
version.startSectionWithMessage("Processing table: TRM_VALUESET");
|
||||
|
@ -117,13 +116,16 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
.addForeignKey("FK_TRM_VALUESET_PID")
|
||||
.toColumn("VALUESET_PID")
|
||||
.references("TRM_VALUESET", "PID");
|
||||
termValueSetConceptTable.addColumn("SYSTEM").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermCodeSystem.MAX_URL_LENGTH);
|
||||
termValueSetConceptTable.addColumn("CODE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermConcept.MAX_CODE_LENGTH);
|
||||
termValueSetConceptTable.addColumn("SYSTEM_URL").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermCodeSystem.MAX_URL_LENGTH);
|
||||
termValueSetConceptTable.addColumn("CODEVAL").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermConcept.MAX_CODE_LENGTH);
|
||||
termValueSetConceptTable
|
||||
.addIndex("IDX_VALUESET_CONCEPT_CS_CD")
|
||||
.unique(false)
|
||||
.withColumns("SYSTEM", "CODE");
|
||||
.withColumns("SYSTEM_URL", "CODEVAL");
|
||||
termValueSetConceptTable.addColumn("DISPLAY").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, TermConcept.MAX_DESC_LENGTH);
|
||||
version.onTable("TRM_VALUESET_CONCEPT")
|
||||
.renameColumn("CODE", "CODEVAL", true, true)
|
||||
.renameColumn("SYSTEM", "SYSTEM_URL", true, true);
|
||||
|
||||
// TermValueSetConceptDesignation
|
||||
version.startSectionWithMessage("Processing table: TRM_VALUESET_C_DESIGNATION");
|
||||
|
|
|
@ -117,6 +117,53 @@ public class BaseMigrationTasks<T extends Enum> {
|
|||
addTask(task);
|
||||
}
|
||||
|
||||
public class BuilderAddTableRawSql {
|
||||
|
||||
private final AddTableRawSqlTask myTask;
|
||||
|
||||
protected BuilderAddTableRawSql(String theTableName) {
|
||||
myTask = new AddTableRawSqlTask();
|
||||
myTask.setTableName(theTableName);
|
||||
addTask(myTask);
|
||||
}
|
||||
|
||||
|
||||
public BuilderAddTableRawSql addSql(DriverTypeEnum theDriverTypeEnum, @Language("SQL") String theSql) {
|
||||
myTask.addSql(theDriverTypeEnum, theSql);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addSql(@Language("SQL") String theSql) {
|
||||
myTask.addSql(theSql);
|
||||
}
|
||||
}
|
||||
|
||||
public class BuilderAddTableByColumns extends BuilderWithTableName implements IAcceptsTasks {
|
||||
private final AddTableByColumnTask myTask;
|
||||
|
||||
public BuilderAddTableByColumns(IAcceptsTasks theSink, String theTableName, String thePkColumnName) {
|
||||
super(theSink, theTableName);
|
||||
myTask = new AddTableByColumnTask();
|
||||
myTask.setTableName(theTableName);
|
||||
myTask.setPkColumn(thePkColumnName);
|
||||
theSink.addTask(myTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderWithTableName.BuilderAddColumnWithName addColumn(String theColumnName) {
|
||||
return new BuilderWithTableName.BuilderAddColumnWithName(theColumnName, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(BaseTask<?> theTask) {
|
||||
if (theTask instanceof AddColumnTask) {
|
||||
myTask.addAddColumnTask((AddColumnTask) theTask);
|
||||
} else {
|
||||
super.addTask(theTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuilderWithTableName implements IAcceptsTasks {
|
||||
private final String myTableName;
|
||||
private final IAcceptsTasks mySink;
|
||||
|
@ -137,6 +184,12 @@ public class BaseMigrationTasks<T extends Enum> {
|
|||
addTask(task);
|
||||
}
|
||||
|
||||
public void dropThisTable() {
|
||||
DropTableTask task = new DropTableTask();
|
||||
task.setTableName(myTableName);
|
||||
addTask(task);
|
||||
}
|
||||
|
||||
public BuilderAddIndexWithName addIndex(String theIndexName) {
|
||||
return new BuilderAddIndexWithName(theIndexName);
|
||||
}
|
||||
|
@ -155,7 +208,7 @@ public class BaseMigrationTasks<T extends Enum> {
|
|||
|
||||
@Override
|
||||
public void addTask(BaseTask<?> theTask) {
|
||||
((BaseTableTask<?>)theTask).setTableName(myTableName);
|
||||
((BaseTableTask<?>) theTask).setTableName(myTableName);
|
||||
mySink.addTask(theTask);
|
||||
}
|
||||
|
||||
|
@ -168,15 +221,22 @@ public class BaseMigrationTasks<T extends Enum> {
|
|||
}
|
||||
|
||||
public BuilderWithTableName renameColumn(String theOldName, String theNewName) {
|
||||
return renameColumn(theOldName, theNewName, false);
|
||||
return renameColumn(theOldName, theNewName, false, false);
|
||||
}
|
||||
|
||||
public BuilderWithTableName renameColumn(String theOldName, String theNewName, boolean theAllowNeitherColumnToExist) {
|
||||
/**
|
||||
* @param theOldName The old column name
|
||||
* @param theNewName The new column name
|
||||
* @param theAllowNeitherColumnToExist Setting this to true means that it's not an error if neither column exists
|
||||
* @param theDeleteTargetColumnFirstIfBothEixst Setting this to true causes the migrator to be ok with the target column existing. It will make sure that there is no data in the column with the new name, then delete it if so in order to make room for the renamed column. If there is data it will still bomb out.
|
||||
*/
|
||||
public BuilderWithTableName renameColumn(String theOldName, String theNewName, boolean theAllowNeitherColumnToExist, boolean theDeleteTargetColumnFirstIfBothEixst) {
|
||||
RenameColumnTask task = new RenameColumnTask();
|
||||
task.setTableName(myTableName);
|
||||
task.setOldName(theOldName);
|
||||
task.setNewName(theNewName);
|
||||
task.setAllowNeitherColumnToExist(theAllowNeitherColumnToExist);
|
||||
task.setDeleteTargetColumnFirstIfBothExist(theDeleteTargetColumnFirstIfBothEixst);
|
||||
addTask(task);
|
||||
return this;
|
||||
}
|
||||
|
@ -210,47 +270,6 @@ public class BaseMigrationTasks<T extends Enum> {
|
|||
}
|
||||
}
|
||||
|
||||
public static class BuilderAddColumnWithName {
|
||||
private final String myColumnName;
|
||||
private final IAcceptsTasks myTaskSink;
|
||||
|
||||
public BuilderAddColumnWithName(String theColumnName, IAcceptsTasks theTaskSink) {
|
||||
myColumnName = theColumnName;
|
||||
myTaskSink = theTaskSink;
|
||||
}
|
||||
|
||||
public BuilderAddColumnWithNameNullable nullable() {
|
||||
return new BuilderAddColumnWithNameNullable(true);
|
||||
}
|
||||
|
||||
public BuilderAddColumnWithNameNullable nonNullable() {
|
||||
return new BuilderAddColumnWithNameNullable(false);
|
||||
}
|
||||
|
||||
public class BuilderAddColumnWithNameNullable {
|
||||
private final boolean myNullable;
|
||||
|
||||
public BuilderAddColumnWithNameNullable(boolean theNullable) {
|
||||
myNullable = theNullable;
|
||||
}
|
||||
|
||||
public void type(AddColumnTask.ColumnTypeEnum theColumnType) {
|
||||
type(theColumnType, null);
|
||||
}
|
||||
|
||||
public void type(AddColumnTask.ColumnTypeEnum theColumnType, Integer theLength) {
|
||||
AddColumnTask task = new AddColumnTask();
|
||||
task.setColumnName(myColumnName);
|
||||
task.setNullable(myNullable);
|
||||
task.setColumnType(theColumnType);
|
||||
if (theLength != null) {
|
||||
task.setColumnLength(theLength);
|
||||
}
|
||||
myTaskSink.addTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BuilderModifyColumnWithName {
|
||||
|
||||
private final String myColumnName;
|
||||
|
@ -334,51 +353,45 @@ public class BaseMigrationTasks<T extends Enum> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BuilderAddTableRawSql {
|
||||
public static class BuilderAddColumnWithName {
|
||||
private final String myColumnName;
|
||||
private final IAcceptsTasks myTaskSink;
|
||||
|
||||
private final AddTableRawSqlTask myTask;
|
||||
public BuilderAddColumnWithName(String theColumnName, IAcceptsTasks theTaskSink) {
|
||||
myColumnName = theColumnName;
|
||||
myTaskSink = theTaskSink;
|
||||
}
|
||||
|
||||
protected BuilderAddTableRawSql(String theTableName) {
|
||||
myTask = new AddTableRawSqlTask();
|
||||
myTask.setTableName(theTableName);
|
||||
addTask(myTask);
|
||||
}
|
||||
public BuilderAddColumnWithNameNullable nullable() {
|
||||
return new BuilderAddColumnWithNameNullable(true);
|
||||
}
|
||||
|
||||
public BuilderAddColumnWithNameNullable nonNullable() {
|
||||
return new BuilderAddColumnWithNameNullable(false);
|
||||
}
|
||||
|
||||
public BuilderAddTableRawSql addSql(DriverTypeEnum theDriverTypeEnum, @Language("SQL") String theSql) {
|
||||
myTask.addSql(theDriverTypeEnum, theSql);
|
||||
return this;
|
||||
}
|
||||
public class BuilderAddColumnWithNameNullable {
|
||||
private final boolean myNullable;
|
||||
|
||||
public void addSql(@Language("SQL") String theSql) {
|
||||
myTask.addSql(theSql);
|
||||
}
|
||||
}
|
||||
public BuilderAddColumnWithNameNullable(boolean theNullable) {
|
||||
myNullable = theNullable;
|
||||
}
|
||||
|
||||
public class BuilderAddTableByColumns extends BuilderWithTableName implements IAcceptsTasks {
|
||||
private final AddTableByColumnTask myTask;
|
||||
public void type(AddColumnTask.ColumnTypeEnum theColumnType) {
|
||||
type(theColumnType, null);
|
||||
}
|
||||
|
||||
public BuilderAddTableByColumns(IAcceptsTasks theSink, String theTableName, String thePkColumnName) {
|
||||
super(theSink, theTableName);
|
||||
myTask = new AddTableByColumnTask();
|
||||
myTask.setTableName(theTableName);
|
||||
myTask.setPkColumn(thePkColumnName);
|
||||
theSink.addTask(myTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderWithTableName.BuilderAddColumnWithName addColumn(String theColumnName) {
|
||||
return new BuilderWithTableName.BuilderAddColumnWithName(theColumnName, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(BaseTask<?> theTask) {
|
||||
if (theTask instanceof AddColumnTask) {
|
||||
myTask.addAddColumnTask((AddColumnTask) theTask);
|
||||
} else {
|
||||
super.addTask(theTask);
|
||||
public void type(AddColumnTask.ColumnTypeEnum theColumnType, Integer theLength) {
|
||||
AddColumnTask task = new AddColumnTask();
|
||||
task.setColumnName(myColumnName);
|
||||
task.setNullable(myNullable);
|
||||
task.setColumnType(theColumnType);
|
||||
if (theLength != null) {
|
||||
task.setColumnLength(theLength);
|
||||
}
|
||||
myTaskSink.addTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,34 @@ import org.junit.Test;
|
|||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class AddIndexTest extends BaseTest {
|
||||
|
||||
@Test
|
||||
public void testIndexAlreadyExists() throws SQLException {
|
||||
public void testUniqueConstraintAlreadyExists() throws SQLException {
|
||||
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255))");
|
||||
executeSql("ALTER TABLE SOMETABLE ADD CONSTRAINT IDX_ANINDEX UNIQUE(TEXTCOL)");
|
||||
|
||||
AddIndexTask task = new AddIndexTask();
|
||||
task.setIndexName("IDX_ANINDEX");
|
||||
task.setTableName("SOMETABLE");
|
||||
task.setColumns("TEXTCOL");
|
||||
task.setUnique(true);
|
||||
getMigrator().addTask(task);
|
||||
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
|
||||
assertThat(JdbcUtils.getIndexNames(getConnectionProperties(), "SOMETABLE"), hasItem("IDX_ANINDEX"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueIndexAlreadyExists() throws SQLException {
|
||||
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255))");
|
||||
executeSql("create unique index IDX_ANINDEX on SOMETABLE (PID, TEXTCOL)");
|
||||
executeSql("create unique index IDX_DIFINDEX on SOMETABLE (TEXTCOL)");
|
||||
|
@ -25,6 +45,30 @@ public class AddIndexTest extends BaseTest {
|
|||
task.setUnique(false);
|
||||
getMigrator().addTask(task);
|
||||
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
|
||||
assertThat(JdbcUtils.getIndexNames(getConnectionProperties(), "SOMETABLE"), containsInAnyOrder("IDX_DIFINDEX", "IDX_ANINDEX"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonUniqueIndexAlreadyExists() throws SQLException {
|
||||
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255))");
|
||||
executeSql("create index IDX_ANINDEX on SOMETABLE (PID, TEXTCOL)");
|
||||
executeSql("create index IDX_DIFINDEX on SOMETABLE (TEXTCOL)");
|
||||
|
||||
AddIndexTask task = new AddIndexTask();
|
||||
task.setIndexName("IDX_ANINDEX");
|
||||
task.setTableName("SOMETABLE");
|
||||
task.setColumns("PID", "TEXTCOL");
|
||||
task.setUnique(false);
|
||||
getMigrator().addTask(task);
|
||||
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
getMigrator().migrate();
|
||||
|
||||
assertThat(JdbcUtils.getIndexNames(getConnectionProperties(), "SOMETABLE"), containsInAnyOrder("IDX_DIFINDEX", "IDX_ANINDEX"));
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||
|
||||
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class DropTableTest extends BaseTest {
|
||||
|
||||
@Test
|
||||
public void testDropExistingTable() throws SQLException {
|
||||
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255))");
|
||||
executeSql("create index IDX_ANINDEX on SOMETABLE (PID, TEXTCOL)");
|
||||
executeSql("create index IDX_DIFINDEX on SOMETABLE (TEXTCOL)");
|
||||
|
||||
DropTableTask task = new DropTableTask();
|
||||
task.setTableName("SOMETABLE");
|
||||
getMigrator().addTask(task);
|
||||
|
||||
assertThat(JdbcUtils.getTableNames(getConnectionProperties()), (hasItems("SOMETABLE")));
|
||||
|
||||
getMigrator().migrate();
|
||||
|
||||
assertThat(JdbcUtils.getTableNames(getConnectionProperties()), not(hasItems("SOMETABLE")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDropNonExistingTable() throws SQLException {
|
||||
|
||||
DropTableTask task = new DropTableTask();
|
||||
task.setTableName("SOMETABLE");
|
||||
getMigrator().addTask(task);
|
||||
|
||||
getMigrator().migrate();
|
||||
|
||||
assertThat(JdbcUtils.getTableNames(getConnectionProperties()), not(hasItems("SOMETABLE")));
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|||
import org.junit.Test;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
|
@ -28,6 +29,46 @@ public class RenameColumnTaskTest extends BaseTest {
|
|||
assertThat(JdbcUtils.getColumnNames(getConnectionProperties(), "SOMETABLE"), containsInAnyOrder("PID", "TEXTCOL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBothExistDeleteTargetFirst() throws SQLException {
|
||||
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255), myTextCol varchar(255))");
|
||||
|
||||
RenameColumnTask task = new RenameColumnTask();
|
||||
task.setTableName("SOMETABLE");
|
||||
task.setDescription("Drop an index");
|
||||
task.setOldName("myTextCol");
|
||||
task.setNewName("TEXTCOL");
|
||||
task.setDeleteTargetColumnFirstIfBothExist(true);
|
||||
getMigrator().addTask(task);
|
||||
|
||||
getMigrator().migrate();
|
||||
|
||||
Set<String> columnNames = JdbcUtils.getColumnNames(getConnectionProperties(), "SOMETABLE");
|
||||
assertThat(columnNames.toString(), columnNames, containsInAnyOrder("PID", "TEXTCOL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBothExistDeleteTargetFirstDataExistsInSourceAndTarget() throws SQLException {
|
||||
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255), myTextCol varchar(255))");
|
||||
executeSql("INSERT INTO SOMETABLE (PID, TEXTCOL, myTextCol) VALUES (123, 'AAA', 'BBB')");
|
||||
|
||||
RenameColumnTask task = new RenameColumnTask();
|
||||
task.setTableName("SOMETABLE");
|
||||
task.setDescription("Drop an index");
|
||||
task.setOldName("myTextCol");
|
||||
task.setNewName("TEXTCOL");
|
||||
task.setDeleteTargetColumnFirstIfBothExist(true);
|
||||
getMigrator().addTask(task);
|
||||
|
||||
try {
|
||||
getMigrator().migrate();
|
||||
fail();
|
||||
} catch (InternalErrorException e) {
|
||||
assertEquals("Failure executing task \"Drop an index\", aborting! Cause: java.sql.SQLException: Can not rename SOMETABLE.myTextCol to TEXTCOL because both columns exist and data exists in TEXTCOL", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColumnDoesntAlreadyExist() throws SQLException {
|
||||
executeSql("create table SOMETABLE (PID bigint not null, myTextCol varchar(255))");
|
||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
|||
import ca.uhn.fhir.spring.boot.autoconfigure.FhirAutoConfiguration.FhirJpaServerConfiguration.Dstu3;
|
||||
import org.assertj.core.util.Arrays;
|
||||
import org.junit.After;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
@ -101,18 +102,21 @@ public class FhirAutoConfigurationTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void withValidation() {
|
||||
load();
|
||||
assertThat(this.context.getBeansOfType(IServerInterceptor.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void withValidations() {
|
||||
load("hapi.fhir.validation.request-only:false");
|
||||
assertThat(this.context.getBeansOfType(IServerInterceptor.class)).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void withCustomValidationSchemaLocation() {
|
||||
load("hapi.fhir.validation.schema-location:custom-schema-location");
|
||||
assertThat(this.context.getBeansOfType(IServerInterceptor.class)).hasSize(1);
|
||||
|
|
|
@ -327,6 +327,11 @@
|
|||
resource as the resource type in order to hold a JSONPatch or XMLPatch body)
|
||||
has been added to the JPA server.
|
||||
</action>
|
||||
<action type="fix" issue="1390">
|
||||
Two issues in the Thymeleaf Narrative Template which caused an error when generating
|
||||
a narrative on an untitled DiagnosticReport were fixed. Thanks to GitHub
|
||||
user @navyflower for reporting!
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.8.0" date="2019-05-30" description="Hippo">
|
||||
<action type="fix">
|
||||
|
|
|
@ -222,7 +222,7 @@
|
|||
<td style="background: #CEC;">4.0.0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HAPI FHIR 3.8.0-SNAPSHOT</td>
|
||||
<td>HAPI FHIR 3.8.0</td>
|
||||
<td>JDK8</td>
|
||||
<td style="background: #DDD;"></td>
|
||||
<td style="background: #CEC;">1.0.2</td>
|
||||
|
|
Loading…
Reference in New Issue