Update to support both JSON and multipart form bodies for create and update.

This commit is contained in:
2023-05-30 11:19:22 -05:00
parent 489f12996d
commit 343f3fe01a
2 changed files with 161 additions and 41 deletions

View File

@ -611,12 +611,50 @@ public class QJavalinImplementation
updateInput.setTableName(table);
PermissionsHelper.checkTablePermissionThrowing(updateInput, TablePermissionSubType.EDIT);
QTableMetaData tableMetaData = qInstance.getTable(table);
QJavalinAccessLogger.logStart("update", logPair("table", table), logPair("primaryKey", primaryKey));
List<QRecord> recordList = new ArrayList<>();
QRecord record = new QRecord();
record.setTableName(table);
recordList.add(record);
record.setValue(tableMetaData.getPrimaryKeyField(), primaryKey);
setRecordValuesForInsertOrUpdate(context, tableMetaData, record);
updateInput.setRecords(recordList);
UpdateAction updateAction = new UpdateAction();
UpdateOutput updateResult = updateAction.execute(updateInput);
QJavalinAccessLogger.logEndSuccess();
context.result(JsonUtils.toJson(updateResult));
}
catch(Exception e)
{
QJavalinAccessLogger.logEndFail(e);
handleException(context, e);
}
}
/*******************************************************************************
**
*******************************************************************************/
private static void setRecordValuesForInsertOrUpdate(Context context, QTableMetaData tableMetaData, QRecord record) throws IOException
{
String contentType = Objects.requireNonNullElse(context.header("content-type"), "");
boolean isContentTypeJson = contentType.toLowerCase().contains("json");
try
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if the caller said they've sent JSON, or if they didn't supply a content-type, then try to read the body //
// as JSON. if it throws, we'll continue by trying to read form params, but if it succeeds, we'll return. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(isContentTypeJson || !StringUtils.hasContent(contentType))
{
Map<?, ?> map = context.bodyAsClass(Map.class);
for(Map.Entry<?, ?> entry : map.entrySet())
{
@ -638,23 +676,38 @@ public class QJavalinImplementation
}
}
QTableMetaData tableMetaData = qInstance.getTable(table);
record.setValue(tableMetaData.getPrimaryKeyField(), primaryKey);
QJavalinAccessLogger.logStart("update", logPair("table", table), logPair("primaryKey", primaryKey));
updateInput.setRecords(recordList);
UpdateAction updateAction = new UpdateAction();
UpdateOutput updateResult = updateAction.execute(updateInput);
QJavalinAccessLogger.logEndSuccess();
context.result(JsonUtils.toJson(updateResult));
return;
}
}
catch(Exception e)
{
QJavalinAccessLogger.logEndFail(e);
handleException(context, e);
LOG.info("Error trying to read body as map", e, logPair("contentType", contentType));
}
/////////////////////////
// process form params //
/////////////////////////
for(Map.Entry<String, List<String>> formParam : context.formParamMap().entrySet())
{
String fieldName = formParam.getKey();
List<String> values = formParam.getValue();
if(CollectionUtils.nullSafeHasContents(values))
{
String value = values.get(0);
if(StringUtils.hasContent(value))
{
record.setValue(fieldName, value);
}
else
{
record.setValue(fieldName, null);
}
}
else
{
// is this ever hit?
record.setValue(fieldName, null);
}
}
}
@ -674,20 +727,13 @@ public class QJavalinImplementation
QJavalinAccessLogger.logStart("insert", logPair("table", tableName));
PermissionsHelper.checkTablePermissionThrowing(insertInput, TablePermissionSubType.INSERT);
QTableMetaData tableMetaData = qInstance.getTable(tableName);
List<QRecord> recordList = new ArrayList<>();
QRecord record = new QRecord();
record.setTableName(tableName);
recordList.add(record);
Map<?, ?> map = context.bodyAsClass(Map.class);
for(Map.Entry<?, ?> entry : map.entrySet())
{
if(StringUtils.hasContent(String.valueOf(entry.getValue())))
{
record.setValue(String.valueOf(entry.getKey()), (Serializable) entry.getValue());
}
}
setRecordValuesForInsertOrUpdate(context, tableMetaData, record);
insertInput.setRecords(recordList);
InsertAction insertAction = new InsertAction();
@ -695,14 +741,14 @@ public class QJavalinImplementation
if(CollectionUtils.nullSafeHasContents(insertOutput.getRecords().get(0).getErrors()))
{
throw (new QUserFacingException("Error inserting " + qInstance.getTable(tableName).getLabel() + ": " + insertOutput.getRecords().get(0).getErrors().get(0)));
throw (new QUserFacingException("Error inserting " + tableMetaData.getLabel() + ": " + insertOutput.getRecords().get(0).getErrors().get(0)));
}
if(CollectionUtils.nullSafeHasContents(insertOutput.getRecords().get(0).getWarnings()))
{
throw (new QUserFacingException("Warning inserting " + qInstance.getTable(tableName).getLabel() + ": " + insertOutput.getRecords().get(0).getWarnings().get(0)));
throw (new QUserFacingException("Warning inserting " + tableMetaData.getLabel() + ": " + insertOutput.getRecords().get(0).getWarnings().get(0)));
}
QJavalinAccessLogger.logEndSuccess(logPair("primaryKey", () -> (insertOutput.getRecords().get(0).getValue(qInstance.getTable(tableName).getPrimaryKeyField()))));
QJavalinAccessLogger.logEndSuccess(logPair("primaryKey", () -> (insertOutput.getRecords().get(0).getValue(tableMetaData.getPrimaryKeyField()))));
context.result(JsonUtils.toJson(insertOutput));
}
catch(Exception e)

View File

@ -391,11 +391,13 @@ class QJavalinImplementationTest extends QJavalinTestBase
/*******************************************************************************
** test an insert
** test an insert - posting the data as a JSON object.
**
** This was the original supported version, but multipart form was added in May 2023
**
*******************************************************************************/
@Test
public void test_dataInsert()
public void test_dataInsertJson()
{
Map<String, Serializable> body = new HashMap<>();
body.put("firstName", "Bobby");
@ -425,11 +427,45 @@ class QJavalinImplementationTest extends QJavalinTestBase
/*******************************************************************************
** test an update
** test an insert - posting a multipart form.
**
*******************************************************************************/
@Test
public void test_dataUpdate()
public void test_dataInsertMultipartForm()
{
HttpResponse<String> response = Unirest.post(BASE_URL + "/data/person")
.header("Content-Type", "application/json")
.multiPartContent()
.field("firstName", "Bobby")
.field("lastName", "Hull")
.field("email", "bobby@hull.com")
.asString();
assertEquals(200, response.getStatus());
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
assertTrue(jsonObject.has("records"));
JSONArray records = jsonObject.getJSONArray("records");
assertEquals(1, records.length());
JSONObject record0 = records.getJSONObject(0);
assertTrue(record0.has("values"));
assertEquals("person", record0.getString("tableName"));
JSONObject values0 = record0.getJSONObject("values");
assertTrue(values0.has("firstName"));
assertEquals("Bobby", values0.getString("firstName"));
assertTrue(values0.has("id"));
assertEquals(7, values0.getInt("id"));
}
/*******************************************************************************
** test an update - posting the data as a JSON object.
**
** This was the original supported version, but multipart form was added in May 2023
**
*******************************************************************************/
@Test
public void test_dataUpdateJson()
{
Map<String, Serializable> body = new HashMap<>();
body.put("firstName", "Free");
@ -465,6 +501,44 @@ class QJavalinImplementationTest extends QJavalinTestBase
/*******************************************************************************
** test an update - posting the data as a multipart form
**
*******************************************************************************/
@Test
public void test_dataUpdateMultipartForm()
{
HttpResponse<String> response = Unirest.patch(BASE_URL + "/data/person/4")
.multiPartContent()
.field("firstName", "Free")
.field("birthDate", "")
.asString();
assertEquals(200, response.getStatus());
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
assertTrue(jsonObject.has("records"));
JSONArray records = jsonObject.getJSONArray("records");
assertEquals(1, records.length());
JSONObject record0 = records.getJSONObject(0);
assertTrue(record0.has("values"));
assertEquals("person", record0.getString("tableName"));
JSONObject values0 = record0.getJSONObject("values");
assertEquals(4, values0.getInt("id"));
assertEquals("Free", values0.getString("firstName"));
///////////////////////////////////////////////////////////////////
// re-GET the record, and validate that birthDate was nulled out //
///////////////////////////////////////////////////////////////////
response = Unirest.get(BASE_URL + "/data/person/4").asString();
assertEquals(200, response.getStatus());
jsonObject = JsonUtils.toJSONObject(response.getBody());
assertTrue(jsonObject.has("values"));
JSONObject values = jsonObject.getJSONObject("values");
assertFalse(values.has("birthDate"));
}
/*******************************************************************************
** test a delete
**