Work on migrator
This commit is contained in:
parent
640ee544c8
commit
bb7fca19a3
|
@ -20,30 +20,29 @@ package ca.uhn.fhir.jpa.util;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.reflect.ClassPath;
|
||||||
|
import com.google.common.reflect.ClassPath.ClassInfo;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.reflect.ClassPath;
|
|
||||||
import com.google.common.reflect.ClassPath.ClassInfo;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|
||||||
|
|
||||||
public class TestUtil {
|
public class TestUtil {
|
||||||
private static final int MAX_LENGTH = 30;
|
private static final int MAX_LENGTH = 30;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestUtil.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestUtil.class);
|
||||||
|
|
||||||
/** non instantiable */
|
/**
|
||||||
|
* non instantiable
|
||||||
|
*/
|
||||||
private TestUtil() {
|
private TestUtil() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -119,6 +118,7 @@ public class TestUtil {
|
||||||
Column column = ae.getAnnotation(Column.class);
|
Column column = ae.getAnnotation(Column.class);
|
||||||
if (column != null) {
|
if (column != null) {
|
||||||
assertNotADuplicateName(column.name(), null);
|
assertNotADuplicateName(column.name(), null);
|
||||||
|
Validate.isTrue(column.unique() == false, "Should not use unique attribute on column (use named @UniqueConstraint instead) on " + ae.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratedValue gen = ae.getAnnotation(GeneratedValue.class);
|
GeneratedValue gen = ae.getAnnotation(GeneratedValue.class);
|
||||||
|
|
|
@ -11,11 +11,21 @@ import javax.annotation.Nonnull;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* Smile CDR - CDR
|
* HAPI FHIR JPA Server - Migration
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2016 - 2018 Simpatico Intelligent Systems Inc
|
* Copyright (C) 2014 - 2018 University Health Network
|
||||||
* %%
|
* %%
|
||||||
* All rights reserved.
|
* 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%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate;
|
package ca.uhn.fhir.jpa.migrate;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.taskdef.BaseTableColumnTypeTask;
|
import ca.uhn.fhir.jpa.migrate.taskdef.BaseTableColumnTypeTask;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -94,7 +114,7 @@ public class JdbcUtils {
|
||||||
case Types.VARCHAR:
|
case Types.VARCHAR:
|
||||||
return BaseTableColumnTypeTask.ColumnTypeEnum.STRING.getDescriptor(length);
|
return BaseTableColumnTypeTask.ColumnTypeEnum.STRING.getDescriptor(length);
|
||||||
case Types.BIGINT:
|
case Types.BIGINT:
|
||||||
return BaseTableColumnTypeTask.ColumnTypeEnum.LONG.getDescriptor(length);
|
return BaseTableColumnTypeTask.ColumnTypeEnum.LONG.getDescriptor(null);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Don't know how to handle datatype: " + dataType);
|
throw new IllegalArgumentException("Don't know how to handle datatype: " + dataType);
|
||||||
}
|
}
|
||||||
|
@ -110,6 +130,32 @@ public class JdbcUtils {
|
||||||
/**
|
/**
|
||||||
* Retrieve all index names
|
* Retrieve all index names
|
||||||
*/
|
*/
|
||||||
|
public static Set<String> getForeignKeys(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName, String theForeignTable) throws SQLException {
|
||||||
|
DataSource dataSource = Objects.requireNonNull(theConnectionProperties.getDataSource());
|
||||||
|
Connection connection = dataSource.getConnection();
|
||||||
|
return theConnectionProperties.getTxTemplate().execute(t -> {
|
||||||
|
DatabaseMetaData metadata;
|
||||||
|
try {
|
||||||
|
metadata = connection.getMetaData();
|
||||||
|
ResultSet indexes = metadata.getCrossReference(null, null, theTableName, null, null, theForeignTable);
|
||||||
|
|
||||||
|
Set<String> columnNames = new HashSet<>();
|
||||||
|
while (indexes.next()) {
|
||||||
|
String fkName = indexes.getString("FK_NAME");
|
||||||
|
fkName = StringUtils.toUpperCase(fkName, Locale.US);
|
||||||
|
columnNames.add(fkName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return columnNames;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve all index names
|
||||||
|
*/
|
||||||
public static Set<String> getColumnNames(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName) throws SQLException {
|
public static Set<String> getColumnNames(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName) throws SQLException {
|
||||||
DataSource dataSource = Objects.requireNonNull(theConnectionProperties.getDataSource());
|
DataSource dataSource = Objects.requireNonNull(theConnectionProperties.getDataSource());
|
||||||
Connection connection = dataSource.getConnection();
|
Connection connection = dataSource.getConnection();
|
||||||
|
@ -162,4 +208,35 @@ public class JdbcUtils {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isColumnNullable(DriverTypeEnum.ConnectionProperties theConnectionProperties, String theTableName, String theColumnName) throws SQLException {
|
||||||
|
DataSource dataSource = Objects.requireNonNull(theConnectionProperties.getDataSource());
|
||||||
|
Connection connection = dataSource.getConnection();
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return theConnectionProperties.getTxTemplate().execute(t -> {
|
||||||
|
DatabaseMetaData metadata;
|
||||||
|
try {
|
||||||
|
metadata = connection.getMetaData();
|
||||||
|
ResultSet tables = metadata.getColumns(null, null, theTableName, theColumnName);
|
||||||
|
|
||||||
|
while (tables.next()) {
|
||||||
|
if (theColumnName.equals(tables.getString("COLUMN_NAME"))) {
|
||||||
|
String nullable = tables.getString("IS_NULLABLE");
|
||||||
|
if ("YES".equals(nullable)) {
|
||||||
|
return true;
|
||||||
|
} else if ("NO".equals(nullable)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unknown nullable: " + nullable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Did not find column " + theColumnName);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new InternalErrorException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate;
|
package ca.uhn.fhir.jpa.migrate;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.taskdef.BaseTask;
|
import ca.uhn.fhir.jpa.migrate.taskdef.BaseTask;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
public class AddForeignKeyTask extends BaseTableColumnTask<AddForeignKeyTask> {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(AddForeignKeyTask.class);
|
||||||
|
private String myConstraintName;
|
||||||
|
private String myForeignTableName;
|
||||||
|
private String myForeignColumnName;
|
||||||
|
|
||||||
|
public void setConstraintName(String theConstraintName) {
|
||||||
|
myConstraintName = theConstraintName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForeignTableName(String theForeignTableName) {
|
||||||
|
myForeignTableName = theForeignTableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForeignColumnName(String theForeignColumnName) {
|
||||||
|
myForeignColumnName = theForeignColumnName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate() {
|
||||||
|
super.validate();
|
||||||
|
|
||||||
|
Validate.isTrue(isNotBlank(myConstraintName));
|
||||||
|
Validate.isTrue(isNotBlank(myForeignTableName));
|
||||||
|
Validate.isTrue(isNotBlank(myForeignColumnName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws SQLException {
|
||||||
|
|
||||||
|
Set<String> existing = JdbcUtils.getForeignKeys(getConnectionProperties(), myForeignTableName, getTableName());
|
||||||
|
if (existing.contains(myConstraintName)) {
|
||||||
|
ourLog.info("Already have constraint named {} - No action performed", myConstraintName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sql = null;
|
||||||
|
switch (getDriverType()) {
|
||||||
|
case MARIADB_10_1:
|
||||||
|
case MYSQL_5_7:
|
||||||
|
sql = "alter table " + getTableName() + " add constraint " + myConstraintName + " foreign key (" + getColumnName() + ") references " + myForeignTableName + " (" + myForeignColumnName + ")";
|
||||||
|
break;
|
||||||
|
case POSTGRES_9_4:
|
||||||
|
case DERBY_EMBEDDED:
|
||||||
|
case ORACLE_12C:
|
||||||
|
case MSSQL_2012:
|
||||||
|
sql = "alter table " + getTableName() + " add constraint " + myConstraintName + " foreign key (" + getColumnName() + ") references " + myForeignTableName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
executeSql(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.DriverTypeEnum;
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.thymeleaf.util.StringUtils;
|
import org.thymeleaf.util.StringUtils;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.DriverTypeEnum;
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -33,12 +53,12 @@ public abstract class BaseTableColumnTypeTask<T extends BaseTableTask> extends B
|
||||||
setColumnType(ColumnTypeEnum.STRING, DriverTypeEnum.ORACLE_12C, "varchar2(?)");
|
setColumnType(ColumnTypeEnum.STRING, DriverTypeEnum.ORACLE_12C, "varchar2(?)");
|
||||||
setColumnType(ColumnTypeEnum.STRING, DriverTypeEnum.POSTGRES_9_4, "varchar(?)");
|
setColumnType(ColumnTypeEnum.STRING, DriverTypeEnum.POSTGRES_9_4, "varchar(?)");
|
||||||
|
|
||||||
setColumnType(ColumnTypeEnum.DATE_TIMESTAMPT, DriverTypeEnum.DERBY_EMBEDDED, "timestamp");
|
setColumnType(ColumnTypeEnum.DATE_TIMESTAMP, DriverTypeEnum.DERBY_EMBEDDED, "timestamp");
|
||||||
setColumnType(ColumnTypeEnum.DATE_TIMESTAMPT, DriverTypeEnum.MARIADB_10_1, "datetime(6)");
|
setColumnType(ColumnTypeEnum.DATE_TIMESTAMP, DriverTypeEnum.MARIADB_10_1, "datetime(6)");
|
||||||
setColumnType(ColumnTypeEnum.DATE_TIMESTAMPT, DriverTypeEnum.MYSQL_5_7, "datetime(6)");
|
setColumnType(ColumnTypeEnum.DATE_TIMESTAMP, DriverTypeEnum.MYSQL_5_7, "datetime(6)");
|
||||||
setColumnType(ColumnTypeEnum.DATE_TIMESTAMPT, DriverTypeEnum.MSSQL_2012, "datetime2");
|
setColumnType(ColumnTypeEnum.DATE_TIMESTAMP, DriverTypeEnum.MSSQL_2012, "datetime2");
|
||||||
setColumnType(ColumnTypeEnum.DATE_TIMESTAMPT, DriverTypeEnum.ORACLE_12C, "timestamp");
|
setColumnType(ColumnTypeEnum.DATE_TIMESTAMP, DriverTypeEnum.ORACLE_12C, "timestamp");
|
||||||
setColumnType(ColumnTypeEnum.DATE_TIMESTAMPT, DriverTypeEnum.POSTGRES_9_4, "timestamp");
|
setColumnType(ColumnTypeEnum.DATE_TIMESTAMP, DriverTypeEnum.POSTGRES_9_4, "timestamp");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColumnTypeEnum getColumnType() {
|
public ColumnTypeEnum getColumnType() {
|
||||||
|
@ -93,7 +113,7 @@ public abstract class BaseTableColumnTypeTask<T extends BaseTableTask> extends B
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getSqlNotNull() {
|
protected String getSqlNotNull() {
|
||||||
return isNullable() ? "" : " not null";
|
return isNullable() ? " null" : " not null";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getColumnLength() {
|
public Long getColumnLength() {
|
||||||
|
@ -121,7 +141,7 @@ public abstract class BaseTableColumnTypeTask<T extends BaseTableTask> extends B
|
||||||
return "varchar(" + theColumnLength + ")";
|
return "varchar(" + theColumnLength + ")";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DATE_TIMESTAMPT{
|
DATE_TIMESTAMP {
|
||||||
@Override
|
@Override
|
||||||
public String getDescriptor(Long theColumnLength) {
|
public String getDescriptor(Long theColumnLength) {
|
||||||
Assert.isTrue(theColumnLength == null, "Must not supply a column length");
|
Assert.isTrue(theColumnLength == null, "Must not supply a column length");
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
public abstract class BaseTableTask<T extends BaseTableTask> extends BaseTask {
|
public abstract class BaseTableTask<T extends BaseTableTask> extends BaseTask {
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.DriverTypeEnum;
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
import org.intellij.lang.annotations.Language;
|
import org.intellij.lang.annotations.Language;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import com.google.common.collect.ForwardingMap;
|
import com.google.common.collect.ForwardingMap;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -16,39 +36,55 @@ public class ModifyColumnTask extends BaseTableColumnTypeTask<ModifyColumnTask>
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
|
||||||
String existingType;
|
String existingType;
|
||||||
|
boolean nullable;
|
||||||
try {
|
try {
|
||||||
existingType = JdbcUtils.getColumnType(getConnectionProperties(), getTableName(), getColumnName());
|
existingType = JdbcUtils.getColumnType(getConnectionProperties(), getTableName(), getColumnName());
|
||||||
|
nullable = JdbcUtils.isColumnNullable(getConnectionProperties(), getTableName(), getColumnName());
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new InternalErrorException(e);
|
throw new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
String wantedType = getColumnType().getDescriptor(getColumnLength());
|
String wantedType = getColumnType().getDescriptor(getColumnLength());
|
||||||
if (existingType.equals(wantedType)) {
|
boolean alreadyOfCorrectType = existingType.equals(wantedType);
|
||||||
ourLog.info("Column {} on table {} is already of type {} - No action performed", getColumnName(), getTableName(), wantedType);
|
boolean alreadyCorrectNullable = isNullable() == nullable;
|
||||||
|
if (alreadyOfCorrectType && alreadyCorrectNullable) {
|
||||||
|
ourLog.info("Column {} on table {} is already of type {} and has nullable {} - No action performed", getColumnName(), getTableName(), wantedType, nullable);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String type = getSqlType();
|
String type = getSqlType();
|
||||||
String notNull = getSqlNotNull();
|
String notNull = getSqlNotNull();
|
||||||
|
|
||||||
String sql;
|
String sql = null;
|
||||||
String sqlNotNull = null;
|
String sqlNotNull = null;
|
||||||
switch (getDriverType()) {
|
switch (getDriverType()) {
|
||||||
case DERBY_EMBEDDED:
|
case DERBY_EMBEDDED:
|
||||||
|
if (!alreadyOfCorrectType) {
|
||||||
sql = "alter table " + getTableName() + " alter column " + getColumnName() + " set data type " + type;
|
sql = "alter table " + getTableName() + " alter column " + getColumnName() + " set data type " + type;
|
||||||
|
}
|
||||||
|
if (!alreadyCorrectNullable) {
|
||||||
|
sqlNotNull = "alter table " + getTableName() + " alter column " + getColumnName() + notNull;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MARIADB_10_1:
|
case MARIADB_10_1:
|
||||||
case MYSQL_5_7:
|
case MYSQL_5_7:
|
||||||
sql = "alter table " + getTableName() + " modify column " + getColumnName() + " " + type + notNull;
|
sql = "alter table " + getTableName() + " modify column " + getColumnName() + " " + type + notNull;
|
||||||
break;
|
break;
|
||||||
case POSTGRES_9_4:
|
case POSTGRES_9_4:
|
||||||
|
if (!alreadyOfCorrectType) {
|
||||||
sql = "alter table " + getTableName() + " alter column " + getColumnName() + " type " + type;
|
sql = "alter table " + getTableName() + " alter column " + getColumnName() + " type " + type;
|
||||||
if (isNullable() == false) {
|
}
|
||||||
|
if (!alreadyCorrectNullable) {
|
||||||
|
if (isNullable()) {
|
||||||
|
sqlNotNull = "alter table " + getTableName() + " alter column " + getColumnName() + " set null";
|
||||||
|
} else {
|
||||||
sqlNotNull = "alter table " + getTableName() + " alter column " + getColumnName() + " set not null";
|
sqlNotNull = "alter table " + getTableName() + " alter column " + getColumnName() + " set not null";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ORACLE_12C:
|
case ORACLE_12C:
|
||||||
sql = "alter table " + getTableName() + " modify " + getColumnName() + " " + type + notNull;
|
String oracleNullableStmt = !alreadyCorrectNullable ? notNull : "";
|
||||||
|
sql = "alter table " + getTableName() + " modify ( " + getColumnName() + " " + type + oracleNullableStmt + " )";
|
||||||
break;
|
break;
|
||||||
case MSSQL_2012:
|
case MSSQL_2012:
|
||||||
sql = "alter table " + getTableName() + " alter column " + getColumnName() + " " + type + notNull;
|
sql = "alter table " + getTableName() + " alter column " + getColumnName() + " " + type + notNull;
|
||||||
|
@ -58,7 +94,9 @@ public class ModifyColumnTask extends BaseTableColumnTypeTask<ModifyColumnTask>
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Updating column {} on table {} to type {}", getColumnName(), getTableName(), type);
|
ourLog.info("Updating column {} on table {} to type {}", getColumnName(), getTableName(), type);
|
||||||
|
if (sql != null) {
|
||||||
executeSql(sql);
|
executeSql(sql);
|
||||||
|
}
|
||||||
|
|
||||||
if (sqlNotNull != null) {
|
if (sqlNotNull != null) {
|
||||||
ourLog.info("Updating column {} on table {} to not null", getColumnName(), getTableName());
|
ourLog.info("Updating column {} on table {} to not null", getColumnName(), getTableName());
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.tasks;
|
package ca.uhn.fhir.jpa.migrate.tasks;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.entity.*;
|
import ca.uhn.fhir.jpa.entity.*;
|
||||||
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
|
@ -11,7 +31,7 @@ import ca.uhn.fhir.jpa.migrate.tasks.api.BaseMigrationTasks;
|
||||||
import ca.uhn.fhir.util.VersionEnum;
|
import ca.uhn.fhir.util.VersionEnum;
|
||||||
|
|
||||||
@SuppressWarnings({"UnstableApiUsage", "SqlNoDataSourceInspection", "SpellCheckingInspection"})
|
@SuppressWarnings({"UnstableApiUsage", "SqlNoDataSourceInspection", "SpellCheckingInspection"})
|
||||||
public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
|
public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -259,7 +279,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
|
||||||
trmConcept
|
trmConcept
|
||||||
.addColumn("CONCEPT_UPDATED")
|
.addColumn("CONCEPT_UPDATED")
|
||||||
.nullable()
|
.nullable()
|
||||||
.type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMPT);
|
.type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP);
|
||||||
trmConcept
|
trmConcept
|
||||||
.addIndex("IDX_CONCEPT_UPDATED")
|
.addIndex("IDX_CONCEPT_UPDATED")
|
||||||
.unique(false)
|
.unique(false)
|
||||||
|
|
|
@ -1,11 +1,30 @@
|
||||||
package ca.uhn.fhir.jpa.migrate.tasks.api;
|
package ca.uhn.fhir.jpa.migrate.tasks.api;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server - Migration
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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.DriverTypeEnum;
|
import ca.uhn.fhir.jpa.migrate.DriverTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.migrate.taskdef.*;
|
import ca.uhn.fhir.jpa.migrate.taskdef.*;
|
||||||
import ca.uhn.fhir.jpa.migrate.tasks.HapiFhirJpaMigrationTasks;
|
|
||||||
import ca.uhn.fhir.util.VersionEnum;
|
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.MultimapBuilder;
|
import com.google.common.collect.MultimapBuilder;
|
||||||
|
import org.apache.commons.lang3.EnumUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.intellij.lang.annotations.Language;
|
import org.intellij.lang.annotations.Language;
|
||||||
|
|
||||||
|
@ -14,24 +33,25 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BaseMigrationTasks {
|
public class BaseMigrationTasks<T extends Enum> {
|
||||||
private Multimap<VersionEnum, BaseTask<?>> myTasks = MultimapBuilder.hashKeys().arrayListValues().build();
|
private Multimap<T, BaseTask<?>> myTasks = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||||
|
|
||||||
public List<BaseTask<?>> getTasks(@Nonnull VersionEnum theFrom, @Nonnull VersionEnum theTo) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public List<BaseTask<?>> getTasks(@Nonnull T theFrom, @Nonnull T theTo) {
|
||||||
Validate.notNull(theFrom);
|
Validate.notNull(theFrom);
|
||||||
Validate.notNull(theTo);
|
Validate.notNull(theTo);
|
||||||
Validate.isTrue(theFrom.ordinal() < theTo.ordinal(), "From version must be lower than to version");
|
Validate.isTrue(theFrom.ordinal() < theTo.ordinal(), "From version must be lower than to version");
|
||||||
|
|
||||||
List<BaseTask<?>> retVal = new ArrayList<>();
|
List<BaseTask<?>> retVal = new ArrayList<>();
|
||||||
for (VersionEnum nextVersion : VersionEnum.values()) {
|
for (Object nextVersion : EnumUtils.getEnumList(theFrom.getClass())) {
|
||||||
if (nextVersion.ordinal() <= theFrom.ordinal()) {
|
if (((T)nextVersion).ordinal() <= theFrom.ordinal()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (nextVersion.ordinal() > theTo.ordinal()) {
|
if (((T)nextVersion).ordinal() > theTo.ordinal()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<BaseTask<?>> nextValues = myTasks.get(nextVersion);
|
Collection<BaseTask<?>> nextValues = myTasks.get((T)nextVersion);
|
||||||
if (nextValues != null) {
|
if (nextValues != null) {
|
||||||
retVal.addAll(nextValues);
|
retVal.addAll(nextValues);
|
||||||
}
|
}
|
||||||
|
@ -40,16 +60,16 @@ public class BaseMigrationTasks {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HapiFhirJpaMigrationTasks.Builder forVersion(VersionEnum theVersion) {
|
protected Builder forVersion(T theVersion) {
|
||||||
return new HapiFhirJpaMigrationTasks.Builder(theVersion);
|
return new Builder(theVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class Builder {
|
protected class Builder {
|
||||||
|
|
||||||
private final VersionEnum myVersion;
|
private final T myVersion;
|
||||||
private String myTableName;
|
private String myTableName;
|
||||||
|
|
||||||
Builder(VersionEnum theVersion) {
|
Builder(T theVersion) {
|
||||||
myVersion = theVersion;
|
myVersion = theVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,14 +88,16 @@ public class BaseMigrationTasks {
|
||||||
return new BuilderAddTable();
|
return new BuilderAddTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startSectionWithMessage(String theMessage) {
|
public Builder startSectionWithMessage(String theMessage) {
|
||||||
Validate.notBlank(theMessage);
|
Validate.notBlank(theMessage);
|
||||||
addTask(new LogStartSectionWithMessageTask(theMessage));
|
addTask(new LogStartSectionWithMessageTask(theMessage));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BuilderWithTableName {
|
public class BuilderWithTableName {
|
||||||
private String myIndexName;
|
private String myIndexName;
|
||||||
private String myColumnName;
|
private String myColumnName;
|
||||||
|
private String myForeignKeyName;
|
||||||
|
|
||||||
public String getTableName() {
|
public String getTableName() {
|
||||||
return myTableName;
|
return myTableName;
|
||||||
|
@ -108,6 +130,11 @@ public class BaseMigrationTasks {
|
||||||
return new BuilderModifyColumnWithName();
|
return new BuilderModifyColumnWithName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BuilderAddForeignKey addForeignKey(String theForeignKeyName) {
|
||||||
|
myForeignKeyName = theForeignKeyName;
|
||||||
|
return new BuilderAddForeignKey();
|
||||||
|
}
|
||||||
|
|
||||||
public class BuilderAddIndexWithName {
|
public class BuilderAddIndexWithName {
|
||||||
private boolean myUnique;
|
private boolean myUnique;
|
||||||
|
|
||||||
|
@ -163,8 +190,15 @@ public class BaseMigrationTasks {
|
||||||
|
|
||||||
public class BuilderModifyColumnWithNameAndNullable {
|
public class BuilderModifyColumnWithNameAndNullable {
|
||||||
|
|
||||||
|
public void withType(BaseTableColumnTypeTask.ColumnTypeEnum theColumnType) {
|
||||||
|
withType(theColumnType, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public void withType(BaseTableColumnTypeTask.ColumnTypeEnum theColumnType, int theLength) {
|
public void withType(BaseTableColumnTypeTask.ColumnTypeEnum theColumnType, int theLength) {
|
||||||
if (theColumnType == BaseTableColumnTypeTask.ColumnTypeEnum.STRING) {
|
if (theColumnType == BaseTableColumnTypeTask.ColumnTypeEnum.STRING) {
|
||||||
|
if (theLength == 0) {
|
||||||
|
throw new IllegalArgumentException("Can not specify length 0 for column of type " + theColumnType);
|
||||||
|
}
|
||||||
ModifyColumnTask task = new ModifyColumnTask();
|
ModifyColumnTask task = new ModifyColumnTask();
|
||||||
task.setColumnName(myColumnName);
|
task.setColumnName(myColumnName);
|
||||||
task.setTableName(myTableName);
|
task.setTableName(myTableName);
|
||||||
|
@ -172,13 +206,32 @@ public class BaseMigrationTasks {
|
||||||
task.setNullable(myNullable);
|
task.setNullable(myNullable);
|
||||||
task.setColumnType(theColumnType);
|
task.setColumnType(theColumnType);
|
||||||
addTask(task);
|
addTask(task);
|
||||||
} else {
|
} else if (theLength > 0){
|
||||||
throw new IllegalArgumentException("Can not specify length for column of type " + theColumnType);
|
throw new IllegalArgumentException("Can not specify length for column of type " + theColumnType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BuilderAddForeignKey extends BuilderModifyColumnWithName {
|
||||||
|
public BuilderAddForeignKeyToColumn toColumn(String theColumnName) {
|
||||||
|
myColumnName = theColumnName;
|
||||||
|
return new BuilderAddForeignKeyToColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BuilderAddForeignKeyToColumn {
|
||||||
|
public void references(String theForeignTable, String theForeignColumn) {
|
||||||
|
AddForeignKeyTask task = new AddForeignKeyTask();
|
||||||
|
task.setTableName(myTableName);
|
||||||
|
task.setConstraintName(myForeignKeyName);
|
||||||
|
task.setColumnName(myColumnName);
|
||||||
|
task.setForeignTableName(theForeignTable);
|
||||||
|
task.setForeignColumnName(theForeignColumn);
|
||||||
|
addTask(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BuilderAddTable {
|
public class BuilderAddTable {
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.migrate.JdbcUtils;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
public class AddForeignKeyTaskTest extends BaseTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddForeignKey() throws SQLException {
|
||||||
|
executeSql("create table HOME (PID bigint not null, TEXTCOL varchar(255), primary key (PID))");
|
||||||
|
executeSql("create table FOREIGNTBL (PID bigint not null, HOMEREF bigint)");
|
||||||
|
assertThat(JdbcUtils.getForeignKeys(getConnectionProperties(), "HOME", "FOREIGNTBL"), empty());
|
||||||
|
|
||||||
|
AddForeignKeyTask task = new AddForeignKeyTask();
|
||||||
|
task.setTableName("FOREIGNTBL");
|
||||||
|
task.setColumnName("HOMEREF");
|
||||||
|
task.setConstraintName("FK_HOME_FOREIGN");
|
||||||
|
task.setForeignColumnName("PID");
|
||||||
|
task.setForeignTableName("HOME");
|
||||||
|
getMigrator().addTask(task);
|
||||||
|
|
||||||
|
getMigrator().migrate();
|
||||||
|
|
||||||
|
assertThat(JdbcUtils.getForeignKeys(getConnectionProperties(), "HOME", "FOREIGNTBL"), Matchers.contains("FK_HOME_FOREIGN"));
|
||||||
|
|
||||||
|
// Make sure additional calls don't crash
|
||||||
|
getMigrator().migrate();
|
||||||
|
getMigrator().migrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -5,9 +5,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
public class ModifyColumnTest extends BaseTest {
|
public class ModifyColumnTest extends BaseTest {
|
||||||
|
|
||||||
|
@ -27,6 +25,90 @@ public class ModifyColumnTest extends BaseTest {
|
||||||
getMigrator().migrate();
|
getMigrator().migrate();
|
||||||
|
|
||||||
assertEquals("varchar(300)", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
assertEquals("varchar(300)", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
|
||||||
|
// Make sure additional migrations don't crash
|
||||||
|
getMigrator().migrate();
|
||||||
|
getMigrator().migrate();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testColumnMakeNullable() throws SQLException {
|
||||||
|
executeSql("create table SOMETABLE (PID bigint not null, TEXTCOL varchar(255) not null)");
|
||||||
|
assertFalse(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertFalse(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
assertEquals("bigint", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertEquals("varchar(255)", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
|
||||||
|
// PID
|
||||||
|
ModifyColumnTask task = new ModifyColumnTask();
|
||||||
|
task.setTableName("SOMETABLE");
|
||||||
|
task.setColumnName("PID");
|
||||||
|
task.setColumnType(AddColumnTask.ColumnTypeEnum.LONG);
|
||||||
|
task.setNullable(true);
|
||||||
|
getMigrator().addTask(task);
|
||||||
|
|
||||||
|
// STRING
|
||||||
|
task = new ModifyColumnTask();
|
||||||
|
task.setTableName("SOMETABLE");
|
||||||
|
task.setColumnName("TEXTCOL");
|
||||||
|
task.setColumnType(AddColumnTask.ColumnTypeEnum.STRING);
|
||||||
|
task.setNullable(true);
|
||||||
|
task.setColumnLength(255);
|
||||||
|
getMigrator().addTask(task);
|
||||||
|
|
||||||
|
// Do migration
|
||||||
|
getMigrator().migrate();
|
||||||
|
|
||||||
|
assertTrue(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertTrue(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
assertEquals("bigint", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertEquals("varchar(255)", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
|
||||||
|
// Make sure additional migrations don't crash
|
||||||
|
getMigrator().migrate();
|
||||||
|
getMigrator().migrate();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testColumnMakeNotNullable() throws SQLException {
|
||||||
|
executeSql("create table SOMETABLE (PID bigint, TEXTCOL varchar(255))");
|
||||||
|
assertTrue(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertTrue(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
assertEquals("bigint", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertEquals("varchar(255)", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
|
||||||
|
// PID
|
||||||
|
ModifyColumnTask task = new ModifyColumnTask();
|
||||||
|
task.setTableName("SOMETABLE");
|
||||||
|
task.setColumnName("PID");
|
||||||
|
task.setColumnType(AddColumnTask.ColumnTypeEnum.LONG);
|
||||||
|
task.setNullable(false);
|
||||||
|
getMigrator().addTask(task);
|
||||||
|
|
||||||
|
// STRING
|
||||||
|
task = new ModifyColumnTask();
|
||||||
|
task.setTableName("SOMETABLE");
|
||||||
|
task.setColumnName("TEXTCOL");
|
||||||
|
task.setColumnType(AddColumnTask.ColumnTypeEnum.STRING);
|
||||||
|
task.setNullable(false);
|
||||||
|
task.setColumnLength(255);
|
||||||
|
getMigrator().addTask(task);
|
||||||
|
|
||||||
|
// Do migration
|
||||||
|
getMigrator().migrate();
|
||||||
|
|
||||||
|
assertFalse(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertFalse(JdbcUtils.isColumnNullable(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
assertEquals("bigint", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "PID"));
|
||||||
|
assertEquals("varchar(255)", JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "TEXTCOL"));
|
||||||
|
|
||||||
|
// Make sure additional migrations don't crash
|
||||||
|
getMigrator().migrate();
|
||||||
|
getMigrator().migrate();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,6 @@ public class HapiFhirJpaMigrationTasksTest {
|
||||||
new HapiFhirJpaMigrationTasks();
|
new HapiFhirJpaMigrationTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue