WIP data tables
This commit is contained in:
@@ -8,6 +8,7 @@ import javax.ws.rs.Consumes;
|
|||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
@@ -124,6 +125,29 @@ public class DataTableApiResource {
|
|||||||
return Response.ok().entity(entityIdentifier).build();
|
return Response.ok().entity(entityIdentifier).build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("{datatable}/{appTableId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public Response updateDatatableEntryOnetoOne(
|
||||||
|
@PathParam("datatable") final String datatable,
|
||||||
|
@PathParam("appTableId") final Long appTableId,
|
||||||
|
final String jsonRequestBody) {
|
||||||
|
|
||||||
|
checkUserPermissionForDatatable(datatable, "UPDATE");
|
||||||
|
Map<String, String> queryParams = getQueryParamsFromJsonRequestBody(jsonRequestBody);
|
||||||
|
|
||||||
|
this.readWriteNonCoreDataService.updateDatatableEntryOnetoOne(datatable,
|
||||||
|
appTableId, queryParams);
|
||||||
|
|
||||||
|
EntityIdentifier entityIdentifier = new EntityIdentifier(
|
||||||
|
Long.valueOf(appTableId));
|
||||||
|
|
||||||
|
return Response.ok().entity(entityIdentifier).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("{datatable}/{appTableId}")
|
@Path("{datatable}/{appTableId}")
|
||||||
@@ -180,7 +204,7 @@ public class DataTableApiResource {
|
|||||||
for (int i = 0; i < jsonArr.length(); i++) {
|
for (int i = 0; i < jsonArr.length(); i++) {
|
||||||
pName = (String) jsonArr.get(i);
|
pName = (String) jsonArr.get(i);
|
||||||
pValue = jsonObj.getString(pName);
|
pValue = jsonObj.getString(pName);
|
||||||
logger.info(pName + " - " + pValue);
|
logger.info("getQueryParamsFromJsonRequestBody: " + pName + " - " + pValue);
|
||||||
queryParams.put(pName, pValue);
|
queryParams.put(pName, pValue);
|
||||||
}
|
}
|
||||||
return queryParams;
|
return queryParams;
|
||||||
|
|||||||
+3
@@ -27,6 +27,9 @@ public interface ReadWriteNonCoreDataService {
|
|||||||
|
|
||||||
void newDatatableEntry(String datatable, Long appTableId,
|
void newDatatableEntry(String datatable, Long appTableId,
|
||||||
Map<String, String> queryParams);
|
Map<String, String> queryParams);
|
||||||
|
|
||||||
|
void updateDatatableEntryOnetoOne(String datatable, Long appTableId,
|
||||||
|
Map<String, String> queryParams);
|
||||||
|
|
||||||
void deleteDatatableEntries(String datatable, Long appTableId);
|
void deleteDatatableEntries(String datatable, Long appTableId);
|
||||||
|
|
||||||
|
|||||||
+219
-10
@@ -12,6 +12,7 @@ import javax.sql.rowset.CachedRowSet;
|
|||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.mifosng.platform.api.data.AdditionalFieldsSetData;
|
import org.mifosng.platform.api.data.AdditionalFieldsSetData;
|
||||||
|
import org.mifosng.platform.api.data.ApiParameterError;
|
||||||
import org.mifosng.platform.api.data.DatatableData;
|
import org.mifosng.platform.api.data.DatatableData;
|
||||||
import org.mifosng.platform.api.data.GenericResultsetData;
|
import org.mifosng.platform.api.data.GenericResultsetData;
|
||||||
import org.mifosng.platform.api.data.ResultsetColumnHeader;
|
import org.mifosng.platform.api.data.ResultsetColumnHeader;
|
||||||
@@ -19,6 +20,7 @@ import org.mifosng.platform.api.data.ResultsetColumnValue;
|
|||||||
import org.mifosng.platform.api.data.ResultsetDataRow;
|
import org.mifosng.platform.api.data.ResultsetDataRow;
|
||||||
import org.mifosng.platform.exceptions.AdditionalFieldsNotFoundException;
|
import org.mifosng.platform.exceptions.AdditionalFieldsNotFoundException;
|
||||||
import org.mifosng.platform.exceptions.DataTableNotFoundException;
|
import org.mifosng.platform.exceptions.DataTableNotFoundException;
|
||||||
|
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
|
||||||
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
|
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
|
||||||
import org.mifosng.platform.security.PlatformSecurityContext;
|
import org.mifosng.platform.security.PlatformSecurityContext;
|
||||||
import org.mifosng.platform.user.domain.AppUser;
|
import org.mifosng.platform.user.domain.AppUser;
|
||||||
@@ -427,19 +429,24 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
+ " not found");
|
+ " not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkMainResourceExistsWithinScope(String tableName,
|
private String getFullDatasetName(final String type, final String set) {
|
||||||
|
return type + "_x" + set;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only exclusively datatable functions below here
|
||||||
|
private void checkMainResourceExistsWithinScope(String appTable,
|
||||||
Long appTableId) {
|
Long appTableId) {
|
||||||
|
|
||||||
String unscopedSql = "select t.id from " + tableName
|
String unscopedSql = "select t.id from " + appTable
|
||||||
+ " t ${dataScopeCriteria} where t.id = " + appTableId;
|
+ " t ${dataScopeCriteria} where t.id = " + appTableId;
|
||||||
|
|
||||||
String sql = dataScopedSQL(unscopedSql, tableName);
|
String sql = dataScopedSQL(unscopedSql, appTable);
|
||||||
|
|
||||||
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : "
|
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : "
|
||||||
+ sql);
|
+ sql);
|
||||||
|
|
||||||
if (rs.size() == 0)
|
if (rs.size() == 0)
|
||||||
throw new DataTableNotFoundException(tableName, appTableId);
|
throw new DataTableNotFoundException(appTable, appTableId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String dataScopedSQL(String unscopedSQL, String appTable) {
|
private String dataScopedSQL(String unscopedSQL, String appTable) {
|
||||||
@@ -475,11 +482,6 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFullDatasetName(final String type, final String set) {
|
|
||||||
return type + "_x" + set;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only exclusively datatable functions below here
|
|
||||||
@Override
|
@Override
|
||||||
public void newDatatableEntry(String datatable, Long appTableId,
|
public void newDatatableEntry(String datatable, Long appTableId,
|
||||||
Map<String, String> queryParams) {
|
Map<String, String> queryParams) {
|
||||||
@@ -502,6 +504,36 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDatatableEntryOnetoOne(String datatable, Long appTableId,
|
||||||
|
Map<String, String> queryParams) {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable,
|
||||||
|
appTableId, null, null);
|
||||||
|
|
||||||
|
if (grs.getData().size() == 0)
|
||||||
|
throw new DataTableNotFoundException(datatable, appTableId);
|
||||||
|
|
||||||
|
String sql = getUpdateSql(grs, datatable,
|
||||||
|
getFKField(getApplicationTableName(datatable)), appTableId,
|
||||||
|
queryParams);
|
||||||
|
|
||||||
|
if (sql != null)
|
||||||
|
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||||
|
else
|
||||||
|
logger.info("No Changes");
|
||||||
|
|
||||||
|
long elapsed = System.currentTimeMillis() - startTime;
|
||||||
|
logger.info("FINISHING updateDatatableEntryOnetoOne: Elapsed Time: "
|
||||||
|
+ elapsed
|
||||||
|
+ " - datatable: "
|
||||||
|
+ datatable
|
||||||
|
+ " id: "
|
||||||
|
+ appTableId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteDatatableEntries(String datatable, Long appTableId) {
|
public void deleteDatatableEntries(String datatable, Long appTableId) {
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
@@ -702,6 +734,27 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getApplicationTableName(String datatable) {
|
||||||
|
// TODO - only used for update... can probably remove this after as its
|
||||||
|
// a reread
|
||||||
|
String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '"
|
||||||
|
+ datatable + "'";
|
||||||
|
|
||||||
|
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : "
|
||||||
|
+ sql);
|
||||||
|
|
||||||
|
if (rs.size() == 0)
|
||||||
|
throw new DataTableNotFoundException(datatable);
|
||||||
|
|
||||||
|
try {
|
||||||
|
rs.next();
|
||||||
|
return rs.getString("application_table_name");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.sql.error",
|
||||||
|
e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getFKField(String applicationTableName) {
|
private String getFKField(String applicationTableName) {
|
||||||
|
|
||||||
return applicationTableName.substring(2) + "_id";
|
return applicationTableName.substring(2) + "_id";
|
||||||
@@ -897,6 +950,97 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
return addSql;
|
return addSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getUpdateSql(GenericResultsetData grs, String datatable,
|
||||||
|
String fkField, Long appTableId, Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
Map<String, String> affectedAndChangedColumns = getAffectedAndChangedColumns(
|
||||||
|
grs, queryParams);
|
||||||
|
|
||||||
|
// just updating fields that have changed since pre-update read - though
|
||||||
|
// its possible these values are different from the page the user was
|
||||||
|
// looking at and even different from the current db values (if some
|
||||||
|
// other update got in quick) - would need a version field for
|
||||||
|
// completeness but its okay to take this risk with additional fields
|
||||||
|
// data
|
||||||
|
|
||||||
|
if (affectedAndChangedColumns.size() == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
String pValue = null;
|
||||||
|
String pValueWrite = "";
|
||||||
|
String singleQuote = "'";
|
||||||
|
boolean firstColumn = true;
|
||||||
|
String sql = "update `" + datatable + "` ";
|
||||||
|
|
||||||
|
for (String key : affectedAndChangedColumns.keySet()) {
|
||||||
|
if (firstColumn) {
|
||||||
|
sql += " set ";
|
||||||
|
firstColumn = false;
|
||||||
|
} else {
|
||||||
|
sql += ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
pValue = affectedAndChangedColumns.get(key);
|
||||||
|
if (StringUtils.isEmpty(pValue)) {
|
||||||
|
pValueWrite = "null";
|
||||||
|
} else {
|
||||||
|
pValueWrite = singleQuote
|
||||||
|
+ genericDataService.replace(pValue, singleQuote,
|
||||||
|
singleQuote + singleQuote) + singleQuote;
|
||||||
|
}
|
||||||
|
sql += "`" + key + "` = " + pValueWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql += " where " + fkField + " = " + appTableId;
|
||||||
|
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getAffectedAndChangedColumns(
|
||||||
|
GenericResultsetData grs, Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
Map<String, String> affectedColumns = getAffectedColumns(
|
||||||
|
grs.getColumnHeaders(), queryParams);
|
||||||
|
Map<String, String> affectedAndChangedColumns = new HashMap<String, String>();
|
||||||
|
String columnValue;
|
||||||
|
|
||||||
|
for (String key : affectedColumns.keySet()) {
|
||||||
|
columnValue = affectedColumns.get(key);
|
||||||
|
if (columnChanged(key, columnValue, grs)) {
|
||||||
|
affectedAndChangedColumns.put(key, columnValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return affectedAndChangedColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean columnChanged(String key, String keyValue,
|
||||||
|
GenericResultsetData grs) {
|
||||||
|
|
||||||
|
List<String> columnValues = grs.getData().get(0).getRow();
|
||||||
|
|
||||||
|
String columnValue = null;
|
||||||
|
for (int i = 0; i < grs.getColumnHeaders().size(); i++) {
|
||||||
|
|
||||||
|
if (key.equals(grs.getColumnHeaders().get(i).getColumnName())) {
|
||||||
|
columnValue = columnValues.get(i);
|
||||||
|
|
||||||
|
if (notTheSame(columnValue, keyValue)) {
|
||||||
|
logger.info("Difference - Column: " + key
|
||||||
|
+ "- Current Value: " + columnValue
|
||||||
|
+ " New Value: " + keyValue);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PlatformDataIntegrityException(
|
||||||
|
"error.msg.invalid.columnName", "Parameter Column Name: " + key
|
||||||
|
+ " not found");
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, String> getAffectedColumns(
|
private Map<String, String> getAffectedColumns(
|
||||||
List<ResultsetColumnHeader> columnHeaders,
|
List<ResultsetColumnHeader> columnHeaders,
|
||||||
Map<String, String> queryParams) {
|
Map<String, String> queryParams) {
|
||||||
@@ -911,7 +1055,7 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
Map<String, String> affectedColumns = new HashMap<String, String>();
|
Map<String, String> affectedColumns = new HashMap<String, String>();
|
||||||
Set<String> keys = queryParams.keySet();
|
Set<String> keys = queryParams.keySet();
|
||||||
for (String key : keys) {
|
for (String key : keys) {
|
||||||
// ignore any id field and matches incoming fields with and without
|
// ignores any id field and matches incoming fields with and without
|
||||||
// underscores (spaces and underscores considered the same)
|
// underscores (spaces and underscores considered the same)
|
||||||
if (!(key.equalsIgnoreCase("id"))) {
|
if (!(key.equalsIgnoreCase("id"))) {
|
||||||
notFound = true;
|
notFound = true;
|
||||||
@@ -925,6 +1069,7 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
if (queryParamColumnUnderscored
|
if (queryParamColumnUnderscored
|
||||||
.equalsIgnoreCase(columnHeaderUnderscored)) {
|
.equalsIgnoreCase(columnHeaderUnderscored)) {
|
||||||
pValue = queryParams.get(key);
|
pValue = queryParams.get(key);
|
||||||
|
validateColumn(columnHeader, pValue);
|
||||||
affectedColumns.put(columnHeader.getColumnName(),
|
affectedColumns.put(columnHeader.getColumnName(),
|
||||||
pValue);
|
pValue);
|
||||||
notFound = false;
|
notFound = false;
|
||||||
@@ -942,6 +1087,69 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
return affectedColumns;
|
return affectedColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateColumn(ResultsetColumnHeader columnHeader,
|
||||||
|
String pValue) {
|
||||||
|
|
||||||
|
if ((StringUtils.isEmpty(pValue))
|
||||||
|
&& (!(columnHeader.isColumnNullable()))) {
|
||||||
|
|
||||||
|
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"error.msg.column.mandatory", columnHeader.getColumnName(),
|
||||||
|
"Mandatory");
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
throw new PlatformApiDataValidationException(
|
||||||
|
"validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check allowed values
|
||||||
|
if ((!StringUtils.isEmpty(pValue))
|
||||||
|
&& columnHeader.getColumnValuesNew().size() > 0) {
|
||||||
|
|
||||||
|
List<ResultsetColumnValue> allowedValues = columnHeader
|
||||||
|
.getColumnValuesNew();
|
||||||
|
if (columnHeader.getColumnType().equalsIgnoreCase("varchar")) {
|
||||||
|
for (ResultsetColumnValue allowedValue : allowedValues) {
|
||||||
|
if (pValue.equalsIgnoreCase(allowedValue.getValue()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"error.msg.invalid.columnValue",
|
||||||
|
columnHeader.getColumnName(), "Value :" + pValue
|
||||||
|
+ "' not found in Allowed Value list");
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
throw new PlatformApiDataValidationException(
|
||||||
|
"validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (columnHeader.getColumnType().equalsIgnoreCase("int")) {
|
||||||
|
for (ResultsetColumnValue allowedValue : allowedValues) {
|
||||||
|
if (pValue.equals(Integer.toString(allowedValue.getId())))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"error.msg.invalid.columnValue",
|
||||||
|
columnHeader.getColumnName(), "Value :" + pValue
|
||||||
|
+ "' not found in Allowed Value list");
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
throw new PlatformApiDataValidationException(
|
||||||
|
"validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PlatformDataIntegrityException(
|
||||||
|
"error.msg.invalid.columnType.", "Code: "
|
||||||
|
+ columnHeader.getColumnName() + " - Invalid Type "
|
||||||
|
+ columnHeader.getColumnType()
|
||||||
|
+ " (neither varchar nor int)");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private String getDeleteEntriesSql(String datatable, String FKField,
|
private String getDeleteEntriesSql(String datatable, String FKField,
|
||||||
Long appTableId) {
|
Long appTableId) {
|
||||||
|
|
||||||
@@ -955,4 +1163,5 @@ public class ReadWriteNonCoreDataServiceImpl implements
|
|||||||
return "delete from `" + datatable + "` where `id` = " + datatableId;
|
return "delete from `" + datatable + "` where `id` = " + datatableId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user