Merge pull request #557 from pramodn02/MIFOSX-517_2

datatable mappings with code and code values implementation
This commit is contained in:
Vishwas Babu A J
2013-09-03 07:17:40 -07:00
12 changed files with 302 additions and 49 deletions
@@ -0,0 +1,11 @@
CREATE TABLE `x_table_cloumn_code_mappings` (
`column_alias_name` VARCHAR(50) NOT NULL,
`code_id` INT(10) NOT NULL,
PRIMARY KEY (`column_alias_name`),
INDEX `FK_x_code_id` (`code_id`),
CONSTRAINT `FK_x_code_id` FOREIGN KEY (`code_id`) REFERENCES `m_code` (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
INSERT INTO `c_configuration` (`name`, `enabled`) VALUES ('constraint_approach_for_datatables', 1);
@@ -10,7 +10,6 @@ package org.mifosplatform.infrastructure.codes.data;
*/
public class CodeData {
@SuppressWarnings("unused")
private final Long id;
@SuppressWarnings("unused")
private final String name;
@@ -26,4 +25,8 @@ public class CodeData {
this.name = name;
this.systemDefined = systemDefined;
}
public Long getCodeId(){
return this.id;
}
}
@@ -14,4 +14,6 @@ public interface CodeReadPlatformService {
Collection<CodeData> retrieveAllCodes();
CodeData retrieveCode(Long codeId);
CodeData retriveCode(String codeName);
}
@@ -71,4 +71,18 @@ public class CodeReadPlatformServiceImpl implements CodeReadPlatformService {
throw new CodeNotFoundException(codeId);
}
}
@Override
public CodeData retriveCode(String codeName) {
try {
context.authenticatedUser();
final CodeMapper rm = new CodeMapper();
final String sql = "select " + rm.schema() + " where c.code_name = ?";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { codeName });
} catch (EmptyResultDataAccessException e) {
throw new CodeNotFoundException(codeName);
}
}
}
@@ -96,8 +96,13 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
final Code code = retrieveCodeBy(codeId);
if (code.isSystemDefined()) { throw new SystemDefinedCodeCannotBeChangedException(); }
this.codeRepository.delete(code);
try {
this.codeRepository.delete(code);
this.codeRepository.flush();
} catch (DataIntegrityViolationException e) {
throw new PlatformDataIntegrityException("error.msg.cund.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + e.getMostSpecificCause());
}
return new CommandProcessingResultBuilder().withEntityId(codeId).build();
}
@@ -13,4 +13,5 @@ public interface ConfigurationDomainService {
boolean isRescheduleRepaymentsOnHolidaysEnabled();
boolean allowTransactionsOnHolidayEnabled();
boolean allowTransactionsOnNonWorkingDayEnabled();
boolean isConstraintApproachEnabledForDatatables();
}
@@ -80,4 +80,11 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
return property.isEnabled();
}
@Override
public boolean isConstraintApproachEnabledForDatatables() {
final String colunnValue = "constraint_approach_for_datatables";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByName(colunnValue);
if (property == null) { throw new GlobalConfigurationPropertyNotFoundException(colunnValue); }
return property.isEnabled();
}
}
@@ -20,7 +20,7 @@ public class PlatformDataIntegrityException extends RuntimeException {
final Object... defaultUserMessageArgs) {
this.globalisationMessageCode = globalisationMessageCode;
this.defaultUserMessage = defaultUserMessage;
this.parameterName = "";
this.parameterName = null;
this.defaultUserMessageArgs = defaultUserMessageArgs;
}
@@ -0,0 +1,11 @@
package org.mifosplatform.infrastructure.core.exception;
public class PlatformServiceUnavailableException extends AbstractPlatformServiceUnavailableException {
public PlatformServiceUnavailableException(String globalisationMessageCode, String defaultUserMessage,
Object... defaultUserMessageArgs) {
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -24,6 +24,7 @@ public final class ResultsetColumnHeaderData {
private final boolean isColumnPrimaryKey;
private final List<ResultsetColumnValueData> columnValues;
private final String columnCode;
public static ResultsetColumnHeaderData basic(final String columnName, final String columnType) {
@@ -31,25 +32,31 @@ public final class ResultsetColumnHeaderData {
final boolean columnNullable = false;
final boolean columnIsPrimaryKey = false;
final List<ResultsetColumnValueData> columnValues = new ArrayList<ResultsetColumnValueData>();
return new ResultsetColumnHeaderData(columnName, columnType, columnLength, columnNullable, columnIsPrimaryKey, columnValues);
final String columnCode = null;
return new ResultsetColumnHeaderData(columnName, columnType, columnLength, columnNullable, columnIsPrimaryKey, columnValues,
columnCode);
}
public static ResultsetColumnHeaderData detailed(final String columnName, final String columnType, final Long columnLength,
final boolean columnNullable, final boolean columnIsPrimaryKey, final List<ResultsetColumnValueData> columnValues) {
return new ResultsetColumnHeaderData(columnName, columnType, columnLength, columnNullable, columnIsPrimaryKey, columnValues);
final boolean columnNullable, final boolean columnIsPrimaryKey, final List<ResultsetColumnValueData> columnValues,
String columnCode) {
return new ResultsetColumnHeaderData(columnName, columnType, columnLength, columnNullable, columnIsPrimaryKey, columnValues,
columnCode);
}
private ResultsetColumnHeaderData(final String columnName, final String columnType, final Long columnLength,
final boolean columnNullable, final boolean columnIsPrimaryKey, final List<ResultsetColumnValueData> columnValues) {
final boolean columnNullable, final boolean columnIsPrimaryKey, final List<ResultsetColumnValueData> columnValues,
String columnCode) {
this.columnName = columnName;
this.columnType = columnType;
this.columnLength = columnLength;
this.isColumnNullable = columnNullable;
this.isColumnPrimaryKey = columnIsPrimaryKey;
this.columnValues = columnValues;
this.columnCode = columnCode;
String displayType = null;
if (this.columnValues.isEmpty()) {
if (this.columnCode == null) {
if (isString()) {
displayType = "STRING";
} else if (isAnyInteger()) {
@@ -228,4 +235,8 @@ public final class ResultsetColumnHeaderData {
}
return allowed;
}
public String getColumnCode() {
return this.columnCode;
}
}
@@ -185,14 +185,34 @@ public class GenericDataServiceImpl implements GenericDataService {
boolean columnIsPrimaryKey = "PRI".equalsIgnoreCase(isPrimaryKey);
List<ResultsetColumnValueData> columnValues = new ArrayList<ResultsetColumnValueData>();
String codeName = null;
if ("varchar".equalsIgnoreCase(columnType)) {
columnValues = retreiveColumnValues(columnName, "_cv");
int codePosition = columnName.indexOf("_cv");
if (codePosition > 0) {
codeName = columnName.substring(0, codePosition);
columnValues = retreiveColumnValues(codeName);
}
} else if ("int".equalsIgnoreCase(columnType)) {
columnValues = retreiveColumnValues(columnName, "_cd");
int codePosition = columnName.indexOf("_cd");
if (codePosition > 0) {
codeName = columnName.substring(0, codePosition);
columnValues = retreiveColumnValues(codeName);
}
}
if(codeName == null){
final SqlRowSet rsValues = getDatatableCodeData(datatable, columnName);
Integer codeId = null;
while (rsValues.next()) {
codeId = rsValues.getInt("id");
codeName = rsValues.getString("code_name");
}
columnValues = retreiveColumnValues(codeId);
}
final ResultsetColumnHeaderData rsch = ResultsetColumnHeaderData.detailed(columnName, columnType, columnLength, columnNullable,
columnIsPrimaryKey, columnValues);
columnIsPrimaryKey, columnValues,codeName);
columnHeaders.add(rsch);
}
@@ -204,14 +224,10 @@ public class GenericDataServiceImpl implements GenericDataService {
* Candidate for using caching there to get allowed 'column values' from
* code/codevalue tables
*/
private List<ResultsetColumnValueData> retreiveColumnValues(final String columnName, final String code_suffix) {
private List<ResultsetColumnValueData> retreiveColumnValues(final String codeName) {
final List<ResultsetColumnValueData> columnValues = new ArrayList<ResultsetColumnValueData>();
int codePosition = columnName.indexOf(code_suffix);
if (codePosition > 0) {
final String codeName = columnName.substring(0, codePosition);
final String sql = "select v.id, v.code_value from m_code m " + " join m_code_value v on v.code_id = m.id "
+ " where m.code_name = '" + codeName + "' order by v.order_position, v.id";
@@ -224,6 +240,23 @@ public class GenericDataServiceImpl implements GenericDataService {
columnValues.add(new ResultsetColumnValueData(id, codeValue));
}
return columnValues;
}
private List<ResultsetColumnValueData> retreiveColumnValues(final Integer codeId) {
final List<ResultsetColumnValueData> columnValues = new ArrayList<ResultsetColumnValueData>();
if (codeId != null) {
final String sql = "select v.id, v.code_value from m_code_value v where v.code_id =" + codeId
+ " order by v.order_position, v.id";
final SqlRowSet rsValues = this.jdbcTemplate.queryForRowSet(sql);
rsValues.beforeFirst();
while (rsValues.next()) {
final Integer id = rsValues.getInt("id");
final String codeValue = rsValues.getString("code_value");
columnValues.add(new ResultsetColumnValueData(id, codeValue));
}
}
return columnValues;
@@ -240,4 +273,13 @@ public class GenericDataServiceImpl implements GenericDataService {
throw new DatatableNotFoundException(datatable);
}
private SqlRowSet getDatatableCodeData(final String datatable, String columnName) {
final String sql = "select mc.id,mc.code_name from m_code mc join x_table_cloumn_code_mappings xcc on xcc.code_id = mc.id where xcc.column_alias_name='"
+ datatable.toLowerCase().replaceAll("\\s", "_") + "_" + columnName + "'";
final SqlRowSet rsValues = this.jdbcTemplate.queryForRowSet(sql);
return rsValues;
}
}
@@ -18,8 +18,11 @@ import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.GenericJDBCException;
import org.hibernate.exception.SQLGrammarException;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.service.CodeReadPlatformService;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -27,6 +30,7 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException;
import org.mifosplatform.infrastructure.core.serialization.DatatableCommandFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.serialization.JsonParserHelper;
@@ -44,6 +48,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
@@ -60,6 +65,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
private final static String DATATABLE_NAME_REGEX_PATTERN = "^[a-zA-Z][a-zA-Z0-9\\-_\\s]{0,48}[a-zA-Z0-9]$";
private final static String CODE_VALUES_TABLE = "m_code_value";
private final static Logger logger = LoggerFactory.getLogger(ReadWriteNonCoreDataServiceImpl.class);
private final static HashMap<String, String> apiTypeToMySQL = new HashMap<String, String>() {
@@ -80,11 +87,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
private final JsonParserHelper helper;
private final GenericDataService genericDataService;
private final DatatableCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final ConfigurationDomainService configurationDomainService;
private final CodeReadPlatformService codeReadPlatformService;
@Autowired
public ReadWriteNonCoreDataServiceImpl(final RoutingDataSource dataSource, final PlatformSecurityContext context,
final FromJsonHelper fromJsonHelper, final GenericDataService genericDataService,
final DatatableCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
final DatatableCommandFromApiJsonDeserializer fromApiJsonDeserializer, final CodeReadPlatformService codeReadPlatformService,
final ConfigurationDomainService configurationDomainService) {
this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
this.context = context;
@@ -92,6 +102,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
this.helper = new JsonParserHelper();
this.genericDataService = genericDataService;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.codeReadPlatformService = codeReadPlatformService;
this.configurationDomainService = configurationDomainService;
}
@Override
@@ -253,7 +265,19 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final String deleteRegisteredDatatableSql = "delete from x_registered_table where registered_table_name = '" + datatable + "'";
String[] sqlArray = { deleteRolePermissionsSql, deletePermissionsSql, deleteRegisteredDatatableSql };
String[] sqlArray = null;
if (configurationDomainService.isConstraintApproachEnabledForDatatables()) {
final String deleteColumnCodeSql = "delete from x_table_cloumn_code_mappings where column_alias_name like'"
+ datatable.toLowerCase().replaceAll("\\s", "_") + "%'";
sqlArray = new String[4];
sqlArray[3] = deleteColumnCodeSql;
} else {
sqlArray = new String[3];
}
sqlArray[0] = deleteRolePermissionsSql;
sqlArray[1] = deletePermissionsSql;
sqlArray[2] = deleteRegisteredDatatableSql;
this.jdbcTemplate.batchUpdate(sqlArray);
}
@@ -333,7 +357,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
"Validation errors exist.", dataValidationErrors); }
}
private void parseDatatableColumnObjectForCreate(final JsonObject column, StringBuilder sqlBuilder) {
private void parseDatatableColumnObjectForCreate(final JsonObject column, StringBuilder sqlBuilder, StringBuilder constrainBuilder,
String dataTableNameAlias, Map<String, Long> codeMappings, boolean isConstraintApproach) {
String name = (column.has("name")) ? column.get("name").getAsString() : null;
String type = (column.has("type")) ? column.get("type").getAsString() : null;
@@ -342,7 +367,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
String code = (column.has("code")) ? column.get("code").getAsString() : null;
if (StringUtils.isNotBlank(code)) {
name = datatableColumnNameToCodeValueName(name, code);
if (isConstraintApproach) {
codeMappings.put(dataTableNameAlias + "_" + name, codeReadPlatformService.retriveCode(code).getCodeId());
constrainBuilder.append(", CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(name).append("` ")
.append("FOREIGN KEY (`" + name + "`) ").append("REFERENCES `").append(CODE_VALUES_TABLE).append("` (`id`)");
} else {
name = datatableColumnNameToCodeValueName(name, code);
}
}
String mysqlType = apiTypeToMySQL.get(type);
@@ -399,10 +430,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
validateDatatableName(datatableName);
validateAppTable(apptableName);
boolean isConstraintApproach = configurationDomainService.isConstraintApproachEnabledForDatatables();
String fkColumnName = apptableName.substring(2) + "_id";
String fkName = datatableName.toLowerCase().replaceAll("\\s", "_") + "_" + fkColumnName;
final String dataTableNameAlias = datatableName.toLowerCase().replaceAll("\\s", "_");
String fkName = dataTableNameAlias + "_" + fkColumnName;
StringBuilder sqlBuilder = new StringBuilder();
StringBuilder constrainBuilder = new StringBuilder();
Map<String, Long> codeMappings = new HashMap<String, Long>();
sqlBuilder = sqlBuilder.append("CREATE TABLE `" + datatableName + "` (");
if (multiRow) {
@@ -413,7 +447,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
for (JsonElement column : columns) {
parseDatatableColumnObjectForCreate(column.getAsJsonObject(), sqlBuilder);
parseDatatableColumnObjectForCreate(column.getAsJsonObject(), sqlBuilder, constrainBuilder, dataTableNameAlias,
codeMappings, isConstraintApproach);
}
// Remove trailing comma and space
@@ -429,10 +464,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
.append("FOREIGN KEY (`" + fkColumnName + "`) ").append("REFERENCES `" + actualAppTableName + "` (`id`)");
}
sqlBuilder.append(constrainBuilder);
sqlBuilder = sqlBuilder.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8;");
this.jdbcTemplate.execute(sqlBuilder.toString());
registerDatatable(datatableName, apptableName);
registerColumnCodeMapping(codeMappings);
} catch (SQLGrammarException e) {
Throwable realCause = e.getCause();
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
@@ -455,7 +493,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
private void parseDatatableColumnForUpdate(final JsonObject column,
final Map<String, ResultsetColumnHeaderData> mapColumnNameDefinition, StringBuilder sqlBuilder) {
final Map<String, ResultsetColumnHeaderData> mapColumnNameDefinition, StringBuilder sqlBuilder, String datatableName,
StringBuilder constrainBuilder, Map<String, Long> codeMappings, List<String> removeMappings, boolean isConstraintApproach) {
String name = (column.has("name")) ? column.get("name").getAsString() : null;
String lengthStr = (column.has("length")) ? column.get("length").getAsString() : null;
@@ -465,20 +504,53 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
String after = (column.has("after")) ? column.get("after").getAsString() : null;
String code = (column.has("code")) ? column.get("code").getAsString() : null;
String newCode = (column.has("newCode")) ? column.get("newCode").getAsString() : null;
String dataTableNameAlias = datatableName.toLowerCase().replaceAll("\\s", "_");
if (isConstraintApproach) {
if (StringUtils.isBlank(newName)) {
newName = name;
}
if (!StringUtils.equalsIgnoreCase(code, newCode) || !StringUtils.equalsIgnoreCase(name, newName)) {
if (StringUtils.equalsIgnoreCase(code, newCode)) {
int codeId = getCodeIdForColumn(dataTableNameAlias, name);
if (codeId > 0) {
removeMappings.add(dataTableNameAlias + "_" + name);
constrainBuilder.append(", DROP FOREIGN KEY `fk_").append(dataTableNameAlias).append("_").append(name).append("` ");
codeMappings.put(dataTableNameAlias + "_" + newName, (long) codeId);
constrainBuilder.append(",ADD CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(newName)
.append("` ").append("FOREIGN KEY (`" + newName + "`) ").append("REFERENCES `").append(CODE_VALUES_TABLE)
.append("` (`id`)");
}
if (StringUtils.isNotBlank(code)) {
name = datatableColumnNameToCodeValueName(name, code);
if (StringUtils.isNotBlank(newCode)) {
newName = datatableColumnNameToCodeValueName(newName, newCode);
} else {
newName = datatableColumnNameToCodeValueName(newName, code);
} else {
if (code != null) {
removeMappings.add(dataTableNameAlias + "_" + name);
if (newCode == null) {
constrainBuilder.append(", DROP FOREIGN KEY `fk_").append(dataTableNameAlias).append("_").append(name)
.append("` ");
}
}
if (newCode != null) {
codeMappings.put(dataTableNameAlias + "_" + newName, codeReadPlatformService.retriveCode(newCode).getCodeId());
if (code == null) {
constrainBuilder.append(",ADD CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(newName)
.append("` ").append("FOREIGN KEY (`" + newName + "`) ").append("REFERENCES `")
.append(CODE_VALUES_TABLE).append("` (`id`)");
}
}
}
}
} else {
if (StringUtils.isNotBlank(code)) {
name = datatableColumnNameToCodeValueName(name, code);
if (StringUtils.isNotBlank(newCode)) {
newName = datatableColumnNameToCodeValueName(newName, newCode);
} else {
newName = datatableColumnNameToCodeValueName(newName, code);
}
}
}
if (!mapColumnNameDefinition.containsKey(name)) { throw new PlatformDataIntegrityException(
"error.msg.datatable.column.missing.update.parse", "Column " + name + " does not exist.", name); }
String type = mapColumnNameDefinition.get(name).getColumnType();
if (length == null && type.toLowerCase().equals("varchar")) {
length = mapColumnNameDefinition.get(name).getColumnLength().intValue();
@@ -505,7 +577,22 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
}
private void parseDatatableColumnForAdd(final JsonObject column, StringBuilder sqlBuilder) {
private int getCodeIdForColumn(String dataTableNameAlias, String name) {
StringBuilder checkColumnCodeMapping = new StringBuilder();
checkColumnCodeMapping.append("select ccm.code_id from x_table_cloumn_code_mappings ccm where ccm.column_alias_name='")
.append(dataTableNameAlias).append("_").append(name).append("'");
int codeId = 0;
try {
codeId = this.jdbcTemplate.queryForInt(checkColumnCodeMapping.toString());
} catch (EmptyResultDataAccessException e) {
logger.info(e.getMessage());
}
return codeId;
}
private void parseDatatableColumnForAdd(final JsonObject column, StringBuilder sqlBuilder, String dataTableNameAlias,
StringBuilder constrainBuilder, Map<String, Long> codeMappings, boolean isConstraintApproach) {
String name = (column.has("name")) ? column.get("name").getAsString() : null;
String type = (column.has("type")) ? column.get("type").getAsString() : null;
@@ -515,7 +602,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
String code = (column.has("code")) ? column.get("code").getAsString() : null;
if (StringUtils.isNotBlank(code)) {
name = datatableColumnNameToCodeValueName(name, code);
if (isConstraintApproach) {
codeMappings.put(dataTableNameAlias + "_" + name, codeReadPlatformService.retriveCode(code).getCodeId());
constrainBuilder.append(",ADD CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(name).append("` ")
.append("FOREIGN KEY (`" + name + "`) ").append("REFERENCES `").append(CODE_VALUES_TABLE).append("` (`id`)");
} else {
name = datatableColumnNameToCodeValueName(name, code);
}
}
String mysqlType = apiTypeToMySQL.get(type);
@@ -542,11 +635,47 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
}
private void parseDatatableColumnForDrop(final JsonObject column, StringBuilder sqlBuilder) {
private void parseDatatableColumnForDrop(final JsonObject column, StringBuilder sqlBuilder, String datatableName,
StringBuilder constrainBuilder, List<String> codeMappings) {
String datatableAlias = datatableName.toLowerCase().replaceAll("\\s", "_");
String name = (column.has("name")) ? column.get("name").getAsString() : null;
sqlBuilder = sqlBuilder.append(", DROP COLUMN `" + name + "`");
StringBuilder findFKSql = new StringBuilder();
findFKSql.append("SELECT count(*)").append("FROM information_schema.TABLE_CONSTRAINTS i")
.append(" WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY'").append(" AND i.TABLE_SCHEMA = DATABASE()")
.append(" AND i.TABLE_NAME = '").append(datatableName).append("' AND i.CONSTRAINT_NAME = 'fk_").append(datatableAlias)
.append("_").append(name).append("' ");
int count = this.jdbcTemplate.queryForInt(findFKSql.toString());
if (count > 0) {
codeMappings.add(datatableAlias + "_" + name);
constrainBuilder.append(", DROP FOREIGN KEY `fk_").append(datatableAlias).append("_").append(name).append("` ");
}
}
private void registerColumnCodeMapping(Map<String, Long> codeMappings) {
if (codeMappings != null && !codeMappings.isEmpty()) {
String[] addSqlList = new String[codeMappings.size()];
int i = 0;
for (Map.Entry<String, Long> mapEntry : codeMappings.entrySet()) {
addSqlList[i++] = "insert into x_table_cloumn_code_mappings (column_alias_name, code_id) values ('" + mapEntry.getKey()
+ "'," + mapEntry.getValue() + ");";
}
this.jdbcTemplate.batchUpdate(addSqlList);
}
}
private void deleteColumnCodeMapping(List<String> columnNames) {
if (columnNames != null && !columnNames.isEmpty()) {
String[] deleteSqlList = new String[columnNames.size()];
int i = 0;
for (String columnName : columnNames) {
deleteSqlList[i++] = "DELETE FROM x_table_cloumn_code_mappings WHERE column_alias_name='" + columnName + "';";
}
this.jdbcTemplate.batchUpdate(deleteSqlList);
}
}
@Transactional
@@ -571,6 +700,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
mapColumnNameDefinition.put(columnHeader.getColumnName(), columnHeader);
}
boolean isConstraintApproach = configurationDomainService.isConstraintApproachEnabledForDatatables();
if (!StringUtils.isBlank(apptableName)) {
validateAppTable(apptableName);
@@ -610,9 +741,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (dropColumns != null) {
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE `" + datatableName + "`");
StringBuilder constrainBuilder = new StringBuilder();
List<String> codeMappings = new ArrayList<String>();
for (JsonElement column : dropColumns) {
parseDatatableColumnForDrop(column.getAsJsonObject(), sqlBuilder);
parseDatatableColumnForDrop(column.getAsJsonObject(), sqlBuilder, datatableName, constrainBuilder, codeMappings);
}
// Remove the first comma, right after ALTER TABLE `datatable`
@@ -620,15 +752,18 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (indexOfFirstComma != -1) {
sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
}
sqlBuilder.append(constrainBuilder);
this.jdbcTemplate.execute(sqlBuilder.toString());
deleteColumnCodeMapping(codeMappings);
}
if (addColumns != null) {
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE `" + datatableName + "`");
StringBuilder constrainBuilder = new StringBuilder();
Map<String, Long> codeMappings = new HashMap<String, Long>();
for (JsonElement column : addColumns) {
parseDatatableColumnForAdd(column.getAsJsonObject(), sqlBuilder);
parseDatatableColumnForAdd(column.getAsJsonObject(), sqlBuilder, datatableName.toLowerCase().replaceAll("\\s", "_"),
constrainBuilder, codeMappings, isConstraintApproach);
}
// Remove the first comma, right after ALTER TABLE `datatable`
@@ -636,15 +771,19 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (indexOfFirstComma != -1) {
sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
}
sqlBuilder.append(constrainBuilder);
this.jdbcTemplate.execute(sqlBuilder.toString());
registerColumnCodeMapping(codeMappings);
}
if (changeColumns != null) {
StringBuilder sqlBuilder = new StringBuilder("ALTER TABLE `" + datatableName + "`");
StringBuilder constrainBuilder = new StringBuilder();
Map<String, Long> codeMappings = new HashMap<String, Long>();
List<String> removeMappings = new ArrayList<String>();
for (JsonElement column : changeColumns) {
parseDatatableColumnForUpdate(column.getAsJsonObject(), mapColumnNameDefinition, sqlBuilder);
parseDatatableColumnForUpdate(column.getAsJsonObject(), mapColumnNameDefinition, sqlBuilder, datatableName,
constrainBuilder, codeMappings, removeMappings, isConstraintApproach);
}
// Remove the first comma, right after ALTER TABLE `datatable`
@@ -652,8 +791,15 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (indexOfFirstComma != -1) {
sqlBuilder = sqlBuilder.deleteCharAt(indexOfFirstComma);
}
this.jdbcTemplate.execute(sqlBuilder.toString());
sqlBuilder.append(constrainBuilder);
try {
this.jdbcTemplate.execute(sqlBuilder.toString());
deleteColumnCodeMapping(removeMappings);
registerColumnCodeMapping(codeMappings);
} catch (GenericJDBCException e) {
if (e.getMessage().contains("Error on rename")) { throw new PlatformServiceUnavailableException(
"error.msg.datatable.column.update.not.allowed", "One of the column name modification not allowed"); }
}
}
} catch (SQLGrammarException e) {
Throwable realCause = e.getCause();