wip update data tables and docs

This commit is contained in:
John Woodlock
2012-09-27 16:58:41 +10:00
parent 471bfe2566
commit d5f697962c
7 changed files with 260 additions and 82 deletions
+173
View File
@@ -2386,7 +2386,180 @@ Request Body:
</div>
</div>
<!-- start of datatables api docs -->
<a id="additionalfields" name="additionalfields" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>Additional Fields (Deprecated)</h3>
<p>
In Mifos X, any number of "Sets" of "Additional Fields" can be configured for a Mifos X database table ("Type").
</p>
<p> For example, portfolio_client is the database table that holds client data. Typically, MFI's want more client related fields than is provided by Mifos X out-of-the-box.
The MFI might add a Set called "Additional Info" containing some fields that are typically input when creating a client.
They might then add another Set called "Highly Improbable Info" containing some fields that are only input in exceptional
circumstances.
</p>
<p>
The additional fields resource allows you to retrieve and update any Additional Fields data that has been configured in Mifos X.
</p>
<p>
The Mifos X Individual Lending client application uses a JQuery plugin called stretchydata which, itself, uses this
additional fields resource to provide a pretty flexible additional fields User Interface (UI).
</p>
</div>
</div>
<a id="additionalfields_list" name="additionalfields_list" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>List Additional Fields Sets</h4>
<p>
Lists the Sets of additional fields have been defined in Mifos X.
</p>
<h5>Arguments</h5>
<dl class="argument-list">
<dt>type</dt>
<dd><span>optional</span></dd>
<dd>The Additional Fields Type (Mifos X database table) to restrict the output to</dd>
</dl>
<p>Example Requests: </p>
<div class=apiClick>additionalfields?type=m_client</div>
<br><br>
<div class=apiClick>additionalfields</div>
</div>
<div class="method-example">
<code class="method-declaration">GET https://Domain Name/api/v1/additionalfields</code>
<code class="method-response">[ {
"id" : 1,
"name" : "Additional Information",
"type" : "portfolio_client"
}, {
"id" : 8,
"name" : "Additional Information",
"type" : "portfolio_loan"
}, {
"id" : 9,
"name" : "Highly Improbable Info",
"type" : "portfolio_client"
} ]
</code>
</div>
</div>
<a id="additionalfields_retrieve" name="additionalfields_retrieve" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve Additional Fields</h4>
<p>
Returns the Set of Additional Fields data for the ID provided. The ID is the id field of the Type table e.g. portfolio_client might have an id value of 4. The output is a JSON formatted "Generic Resultset". The Generic Resultset contains Column Heading as well as Data information. The Column Heading information may include allowed values (columnValues array).
</p>
<p>Example Request:
<div class=apiClick>additionalfields/m_client/Additional Information/2</div>
</p>
</div>
<div class="method-example">
<code class="method-declaration">GET https://Domain Name/api/v1/additionalfields/{type}/{set}/{id}</code>
<code class="method-response">{
"columnHeaders" : [ {
"columnName" : "Ethnic Group",
"columnType" : "String",
"columnLength" : 50,
"columnDisplayType" : "List",
"columnValues" : [ "Bedouin", "Berber", "Italian", "Miknasa", "Mrazig", "Other", "Unknown" ]
}, {
"columnName" : "Ethnic Group Other",
"columnType" : "String",
"columnLength" : 50,
"columnDisplayType" : null,
"columnValues" : [ ]
}, {
"columnName" : "Household Location",
"columnType" : "String",
"columnLength" : 50,
"columnDisplayType" : "List",
"columnValues" : [ "East Sikkim", "North Sikkim", "South Sikkim", "West Sikkim", "Other" ]
}, {
"columnName" : "Household Location Other",
"columnType" : "String",
"columnLength" : 50,
"columnDisplayType" : null,
"columnValues" : [ ]
}, {
"columnName" : "Religion",
"columnType" : "String",
"columnLength" : 50,
"columnDisplayType" : "List",
"columnValues" : [ "Protestant", "Catholic", "Muslim", "Animist", "Atheist", "Other", "Unknown" ]
}, {
"columnName" : "Religion Other",
"columnType" : "String",
"columnLength" : 50,
"columnDisplayType" : null,
"columnValues" : [ ]
}, {
"columnName" : "Knowledge of Person",
"columnType" : "String",
"columnLength" : 50,
"columnDisplayType" : "List",
"columnValues" : [ "Staff member", "Spouse of staff member", "Son/daughter of staff member", "Friend of staff member", "Not known by any staff member", "Other" ]
}, {
"columnName" : "Gender",
"columnType" : "String",
"columnLength" : 10,
"columnDisplayType" : "List",
"columnValues" : [ "Female", "Male" ]
}, {
"columnName" : "Whois",
"columnType" : "Text",
"columnLength" : null,
"columnDisplayType" : null,
"columnValues" : [ ]
} ],
"data" : [ {
"row" : [ "Bedouin", null, "East Sikkim", null, "Animist", "Agnostic", "Friend of staff member", "Female", "A person of honesty & clear thought" ]
} ]
}
</code>
</div>
</div>
<a id="additionalfields_update" name="additionalfields_update" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Update Additional Fields</h4>
<p>
Updates (or creates) the Set of Additional Fields data for the ID provided. The ID is the id field of the Type table e.g. portfolio_client might have an id value of 4.
</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/additionalfields/{type}/{set}/{id}</code>
<code class="method-request">POST additionalfields/portfolio_client/Additional Information/2
Content-Type: application/json
Request Body:
{
"Ethnic_Group":"Berber",
"Ethnic_Group_Other":"",
"Household_Location":"East Sikkim",
"Household_Location_Other":"",
"Religion":"Animist",
"Religion_Other":"jjjjjjj",
"Knowledge_of_Person":"Son/daughter of staff member",
"Gender":"Female",
"Whois":"its\r\nme of\r\ncourse\r\nyes\r\nend and the end of it all"
}
</code>
<code class="method-response">{
"entityId": 2
}
</code>
</div>
</div>
<!-- start of reports api docs -->
<a id="reports" name="reports" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
@@ -29,6 +29,7 @@ import org.mifosng.platform.api.data.GenericResultsetData;
import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService;
import org.mifosng.platform.api.infrastructure.ApiParameterHelper;
import org.mifosng.platform.exceptions.NoAuthorizationException;
import org.mifosng.platform.noncore.GenericDataService;
import org.mifosng.platform.noncore.ReadWriteNonCoreDataService;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
@@ -53,6 +54,9 @@ public class DataTableApiResource {
this.context = context;
}
@Autowired
private GenericDataService genericDataService;
@Autowired
private ReadWriteNonCoreDataService readWriteNonCoreDataService;
@@ -113,21 +117,23 @@ public class DataTableApiResource {
checkUserPermissionForDatatable(datatable, "READ");
/*
* Dont use this for now... but its the code for returning data as json
* objects rather than a generic resultset String resultStr =
* this.readWriteNonCoreDataService
* .retrieveDataTableJSONObject(datatable, id, sqlFields, sqlOrder);
*/
GenericResultsetData results = this.readWriteNonCoreDataService
.retrieveDataTableGenericResultSet(datatable, apptableId,
sqlFields, sqlOrder, null);
boolean prettyPrints = ApiParameterHelper.prettyPrint(uriInfo
boolean genericResultSet = ApiParameterHelper.genericResultSet(uriInfo
.getQueryParameters());
return this.apiJsonSerializerService
.serializeGenericResultsetDataToJson(prettyPrints, results);
if (genericResultSet) {
boolean prettyPrints = ApiParameterHelper.prettyPrint(uriInfo
.getQueryParameters());
return this.apiJsonSerializerService
.serializeGenericResultsetDataToJson(prettyPrints, results);
} else {
return this.genericDataService
.generateJsonFromGenericResultsetData(results);
}
}
@@ -60,7 +60,7 @@ public class ApiParameterHelper {
}
return parameterType;
}
public static boolean template(final MultivaluedMap<String, String> queryParams) {
boolean template = false;
if (queryParams.getFirst("template") != null) {
@@ -69,4 +69,13 @@ public class ApiParameterHelper {
}
return template;
}
public static boolean genericResultSet(final MultivaluedMap<String, String> queryParams) {
boolean genericResultSet = false;
if (queryParams.getFirst("genericResultSet") != null) {
String genericResultSetValue = queryParams.getFirst("genericResultSet");
genericResultSet = "true".equalsIgnoreCase(genericResultSetValue);
}
return genericResultSet;
}
}
@@ -12,6 +12,8 @@ public interface GenericDataService {
GenericResultsetData fillGenericResultSet(final String sql);
String generateJsonFromGenericResultsetData(GenericResultsetData grs);
String replace(String str, String pattern, String replace);
String wrapSQL(String sql);
@@ -11,6 +11,7 @@ import java.util.List;
import javax.sql.DataSource;
import javax.sql.rowset.CachedRowSet;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.data.GenericResultsetData;
import org.mifosng.platform.api.data.ResultsetColumnHeader;
import org.mifosng.platform.api.data.ResultsetDataRow;
@@ -22,7 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sun.rowset.CachedRowSetImpl;
//TODO - Performance Item - most items (code values etc) can be cached but not doing that yet
@Service
public class GenericDataServiceImpl implements GenericDataService {
@@ -39,6 +40,7 @@ public class GenericDataServiceImpl implements GenericDataService {
@Override
public CachedRowSet getCachedResultSet(String sql, String sqlErrorMsg) {
//TODO - Need to reimplement this away from Sun library - could be mixture of Lists and jdbcTemplate.query
long startTime = System.currentTimeMillis();
Connection db_connection = null;
@@ -157,6 +159,62 @@ public class GenericDataServiceImpl implements GenericDataService {
return "select x.* from (" + sql + ") x";
}
@Override
public String generateJsonFromGenericResultsetData(GenericResultsetData grs) {
StringBuffer writer = new StringBuffer();
writer.append("[");
List<ResultsetColumnHeader> columnHeaders = grs.getColumnHeaders();
logger.info("NO. of Columns: " + columnHeaders.size());
List<ResultsetDataRow> data = grs.getData();
List<String> row;
Integer rSize;
String currColType;
String currVal;
logger.info("NO. of Rows: " + data.size());
for (int i = 0; i < data.size(); i++) {
writer.append("\n{");
row = data.get(i).getRow();
rSize = row.size();
for (int j = 0; j < rSize; j++) {
writer.append('\"' + columnHeaders.get(j).getColumnName()
+ '\"' + ": ");
currColType = columnHeaders.get(j).getColumnDisplayTypeNew();
currVal = row.get(j);
if (currVal != null) {
if (currColType.equals("DECIMAL")
|| currColType.equals("INTEGER"))
writer.append(currVal);
else {
if (currColType.equals("DATE")) {
LocalDate localDate = new LocalDate(currVal);
writer.append("[" + localDate.getYear() + ", " + localDate.getMonthOfYear() + ", " + localDate.getDayOfMonth() + "]");
} else
writer.append('\"' + currVal + '\"');
}
} else
writer.append("null");
if (j < (rSize - 1))
writer.append(",\n");
}
if (i < (data.size() - 1))
writer.append("},");
else
writer.append("}");
}
writer.append("\n]");
return writer.toString();
}
private void dbClose(Statement db_statement, Connection db_connection) {
logger.debug("dbClose");
try {
@@ -20,9 +20,6 @@ public interface ReadWriteNonCoreDataService {
GenericResultsetData retrieveDataTableGenericResultSet(String datatable,
Long appTableId, String sqlFields, String sqlOrder, Long id);
String retrieveDataTableJSONObject(String datatable, Long appTableId,
String sqlFields, String sqlOrder);
void newDatatableEntry(String datatable, Long appTableId,
Map<String, String> queryParams);
@@ -294,22 +294,6 @@ public class ReadWriteNonCoreDataServiceImpl implements
}
@Override
public String retrieveDataTableJSONObject(String datatable,
Long appTableId, String sqlFields, String sqlOrder) {
long startTime = System.currentTimeMillis();
GenericResultsetData result = retrieveDataTableGenericResultSet(
datatable, appTableId, sqlFields, sqlOrder, null);
String jsonString = generateJsonFromGenericResultsetData(result);
long elapsed = System.currentTimeMillis() - startTime;
logger.info("FINISHING DATATABLE JSON OBJECT: " + datatable
+ " Elapsed Time: " + elapsed);
return jsonString;
}
@Override
public GenericResultsetData retrieveDataTableGenericResultSet(
String datatable, Long appTableId, String sqlFields,
@@ -595,57 +579,6 @@ public class ReadWriteNonCoreDataServiceImpl implements
}
private static String generateJsonFromGenericResultsetData(
GenericResultsetData result) {
StringBuffer writer = new StringBuffer();
writer.append("[");
List<ResultsetColumnHeader> columnHeaders = result.getColumnHeaders();
logger.info("NO. of Columns: " + columnHeaders.size());
List<ResultsetDataRow> data = result.getData();
List<String> row;
Integer rSize;
String currColType;
String currVal;
logger.info("NO. of Rows: " + data.size());
for (int i = 0; i < data.size(); i++) {
writer.append("\n{");
row = data.get(i).getRow();
rSize = row.size();
for (int j = 0; j < rSize; j++) {
writer.append('\"' + columnHeaders.get(j).getColumnName()
+ '\"' + ": ");
currColType = columnHeaders.get(j).getColumnDisplayTypeNew();
currVal = row.get(j);
if (currVal != null) {
if (currColType.equals("DECIMAL")
|| currColType.equals("INTEGER"))
writer.append(currVal);
else
writer.append('\"' + currVal + '\"');
} else
writer.append("null");
if (j < (rSize - 1))
writer.append(",\n");
}
if (i < (data.size() - 1))
writer.append("},");
else
writer.append("}");
}
writer.append("\n]");
return writer.toString();
}
private String getAddSql(List<ResultsetColumnHeader> columnHeaders,
String datatable, String fkName, Long appTableId,
Map<String, String> queryParams) {