mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Convert QRecord errors and warnings to new QStatusMessage type hierarchy.
This commit is contained in:
@ -68,6 +68,12 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.NotFoundStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.PermissionDeniedMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QErrorMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.Pair;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
@ -364,12 +370,12 @@ public class ApiImplementation
|
||||
InsertAction insertAction = new InsertAction();
|
||||
InsertOutput insertOutput = insertAction.execute(insertInput);
|
||||
|
||||
List<String> errors = insertOutput.getRecords().get(0).getErrors();
|
||||
List<QErrorMessage> errors = insertOutput.getRecords().get(0).getErrors();
|
||||
if(CollectionUtils.nullSafeHasContents(errors))
|
||||
{
|
||||
boolean isBadRequest = areAnyErrorsBadRequest(errors);
|
||||
|
||||
String message = "Error inserting " + table.getLabel() + ": " + StringUtils.joinWithCommasAndAnd(errors);
|
||||
String message = "Error inserting " + table.getLabel() + ": " + joinErrorsWithCommasAndAnd(errors);
|
||||
if(isBadRequest)
|
||||
{
|
||||
throw (new QBadRequestException(message));
|
||||
@ -383,10 +389,10 @@ public class ApiImplementation
|
||||
LinkedHashMap<String, Serializable> outputRecord = new LinkedHashMap<>();
|
||||
outputRecord.put(table.getPrimaryKeyField(), insertOutput.getRecords().get(0).getValue(table.getPrimaryKeyField()));
|
||||
|
||||
List<String> warnings = insertOutput.getRecords().get(0).getWarnings();
|
||||
List<QWarningMessage> warnings = insertOutput.getRecords().get(0).getWarnings();
|
||||
if(CollectionUtils.nullSafeHasContents(warnings))
|
||||
{
|
||||
outputRecord.put("warning", "Warning inserting " + table.getLabel() + ", some data may have been inserted: " + StringUtils.joinWithCommasAndAnd(warnings));
|
||||
outputRecord.put("warning", "Warning inserting " + table.getLabel() + ", some data may have been inserted: " + joinErrorsWithCommasAndAnd(warnings));
|
||||
}
|
||||
|
||||
return (outputRecord);
|
||||
@ -463,19 +469,19 @@ public class ApiImplementation
|
||||
LinkedHashMap<String, Serializable> outputRecord = new LinkedHashMap<>();
|
||||
response.add(outputRecord);
|
||||
|
||||
List<String> errors = record.getErrors();
|
||||
List<String> warnings = record.getWarnings();
|
||||
List<QErrorMessage> errors = record.getErrors();
|
||||
List<QWarningMessage> warnings = record.getWarnings();
|
||||
if(CollectionUtils.nullSafeHasContents(errors))
|
||||
{
|
||||
outputRecord.put("statusCode", HttpStatus.Code.BAD_REQUEST.getCode());
|
||||
outputRecord.put("statusText", HttpStatus.Code.BAD_REQUEST.getMessage());
|
||||
outputRecord.put("error", "Error inserting " + table.getLabel() + ": " + StringUtils.joinWithCommasAndAnd(errors));
|
||||
outputRecord.put("error", "Error inserting " + table.getLabel() + ": " + joinErrorsWithCommasAndAnd(errors));
|
||||
}
|
||||
else if(CollectionUtils.nullSafeHasContents(warnings))
|
||||
{
|
||||
outputRecord.put("statusCode", HttpStatus.Code.CREATED.getCode());
|
||||
outputRecord.put("statusText", HttpStatus.Code.CREATED.getMessage());
|
||||
outputRecord.put("warning", "Warning inserting " + table.getLabel() + ", some data may have been inserted: " + StringUtils.joinWithCommasAndAnd(warnings));
|
||||
outputRecord.put("warning", "Warning inserting " + table.getLabel() + ", some data may have been inserted: " + joinErrorsWithCommasAndAnd(warnings));
|
||||
outputRecord.put(table.getPrimaryKeyField(), record.getValue(table.getPrimaryKeyField()));
|
||||
}
|
||||
else
|
||||
@ -570,7 +576,7 @@ public class ApiImplementation
|
||||
UpdateAction updateAction = new UpdateAction();
|
||||
UpdateOutput updateOutput = updateAction.execute(updateInput);
|
||||
|
||||
List<String> errors = updateOutput.getRecords().get(0).getErrors();
|
||||
List<QErrorMessage> errors = updateOutput.getRecords().get(0).getErrors();
|
||||
if(CollectionUtils.nullSafeHasContents(errors))
|
||||
{
|
||||
if(areAnyErrorsNotFound(errors))
|
||||
@ -581,7 +587,7 @@ public class ApiImplementation
|
||||
{
|
||||
boolean isBadRequest = areAnyErrorsBadRequest(errors);
|
||||
|
||||
String message = "Error updating " + table.getLabel() + ": " + StringUtils.joinWithCommasAndAnd(errors);
|
||||
String message = "Error updating " + table.getLabel() + ": " + joinErrorsWithCommasAndAnd(errors);
|
||||
if(isBadRequest)
|
||||
{
|
||||
throw (new QBadRequestException(message));
|
||||
@ -679,10 +685,10 @@ public class ApiImplementation
|
||||
//////////
|
||||
}
|
||||
|
||||
List<String> errors = record.getErrors();
|
||||
List<QErrorMessage> errors = record.getErrors();
|
||||
if(CollectionUtils.nullSafeHasContents(errors))
|
||||
{
|
||||
outputRecord.put("error", "Error updating " + table.getLabel() + ": " + StringUtils.joinWithCommasAndAnd(errors));
|
||||
outputRecord.put("error", "Error updating " + table.getLabel() + ": " + joinErrorsWithCommasAndAnd(errors));
|
||||
if(areAnyErrorsNotFound(errors))
|
||||
{
|
||||
outputRecord.put("statusCode", HttpStatus.Code.NOT_FOUND.getCode());
|
||||
@ -729,13 +735,14 @@ public class ApiImplementation
|
||||
DeleteOutput deleteOutput = deleteAction.execute(deleteInput);
|
||||
if(CollectionUtils.nullSafeHasContents(deleteOutput.getRecordsWithErrors()))
|
||||
{
|
||||
if(areAnyErrorsNotFound(deleteOutput.getRecordsWithErrors().get(0).getErrors()))
|
||||
List<QErrorMessage> errors = deleteOutput.getRecordsWithErrors().get(0).getErrors();
|
||||
if(areAnyErrorsNotFound(errors))
|
||||
{
|
||||
throw (new QNotFoundException("Could not find " + table.getLabel() + " with " + table.getFields().get(table.getPrimaryKeyField()).getLabel() + " of " + primaryKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new QException("Error deleting " + table.getLabel() + ": " + StringUtils.joinWithCommasAndAnd(deleteOutput.getRecordsWithErrors().get(0).getErrors())));
|
||||
throw (new QException("Error deleting " + table.getLabel() + ": " + joinErrorsWithCommasAndAnd(errors)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -811,8 +818,8 @@ public class ApiImplementation
|
||||
///////////////////////////////////////
|
||||
List<Map<String, Serializable>> response = new ArrayList<>();
|
||||
|
||||
List<QRecord> recordsWithErrors = deleteOutput.getRecordsWithErrors();
|
||||
Map<String, List<String>> primaryKeyToErrorsMap = new HashMap<>();
|
||||
List<QRecord> recordsWithErrors = deleteOutput.getRecordsWithErrors();
|
||||
Map<String, List<QErrorMessage>> primaryKeyToErrorsMap = new HashMap<>();
|
||||
for(QRecord recordWithError : CollectionUtils.nonNullList(recordsWithErrors))
|
||||
{
|
||||
String primaryKey = recordWithError.getValueString(table.getPrimaryKeyField());
|
||||
@ -825,11 +832,11 @@ public class ApiImplementation
|
||||
response.add(outputRecord);
|
||||
outputRecord.put(table.getPrimaryKeyField(), primaryKey);
|
||||
|
||||
String primaryKeyString = ValueUtils.getValueAsString(primaryKey);
|
||||
List<String> errors = primaryKeyToErrorsMap.get(primaryKeyString);
|
||||
String primaryKeyString = ValueUtils.getValueAsString(primaryKey);
|
||||
List<QErrorMessage> errors = primaryKeyToErrorsMap.get(primaryKeyString);
|
||||
if(CollectionUtils.nullSafeHasContents(errors))
|
||||
{
|
||||
outputRecord.put("error", "Error deleting " + table.getLabel() + ": " + StringUtils.joinWithCommasAndAnd(errors));
|
||||
outputRecord.put("error", "Error deleting " + table.getLabel() + ": " + joinErrorsWithCommasAndAnd(errors));
|
||||
if(areAnyErrorsNotFound(errors))
|
||||
{
|
||||
outputRecord.put("statusCode", HttpStatus.Code.NOT_FOUND.getCode());
|
||||
@ -853,6 +860,16 @@ public class ApiImplementation
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static String joinErrorsWithCommasAndAnd(List<? extends QStatusMessage> errors)
|
||||
{
|
||||
return StringUtils.joinWithCommasAndAnd(errors.stream().map(QStatusMessage::getMessage).toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -1109,13 +1126,9 @@ public class ApiImplementation
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static boolean areAnyErrorsBadRequest(List<String> errors)
|
||||
private static boolean areAnyErrorsBadRequest(List<QErrorMessage> errors)
|
||||
{
|
||||
boolean isBadRequest = errors.stream().anyMatch(e ->
|
||||
e.contains("Missing value in required field")
|
||||
|| e.contains("You do not have permission")
|
||||
);
|
||||
return isBadRequest;
|
||||
return errors.stream().anyMatch(e -> (e instanceof BadInputStatusMessage) || (e instanceof PermissionDeniedMessage));
|
||||
}
|
||||
|
||||
|
||||
@ -1123,9 +1136,9 @@ public class ApiImplementation
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static boolean areAnyErrorsNotFound(List<String> errors)
|
||||
private static boolean areAnyErrorsNotFound(List<QErrorMessage> errors)
|
||||
{
|
||||
return errors.stream().anyMatch(e -> e.startsWith(UpdateAction.NOT_FOUND_ERROR_PREFIX) || e.startsWith(DeleteAction.NOT_FOUND_ERROR_PREFIX));
|
||||
return errors.stream().anyMatch(e -> (e instanceof NotFoundStatusMessage));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,6 +52,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Association;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
@ -156,7 +158,7 @@ public class TestUtils
|
||||
{
|
||||
if(!record.getValueString("firstName").matches(".*[a-z].*"))
|
||||
{
|
||||
record.addWarning("First name does not contain any letters...");
|
||||
record.addWarning(new QWarningMessage("First name does not contain any letters..."));
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,6 +240,7 @@ public class TestUtils
|
||||
{
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME_ORDER)
|
||||
.withCustomizer(TableCustomizers.PRE_INSERT_RECORD.getRole(), new QCodeReference(OrderPreInsertCustomizer.class))
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withMiddlewareMetaData(new ApiTableMetaDataContainer().withApiTableMetaData(TestUtils.API_NAME, new ApiTableMetaData().withInitialVersion(V2022_Q4)))
|
||||
.withPrimaryKeyField("id")
|
||||
@ -398,4 +401,37 @@ public class TestUtils
|
||||
insertPersonRecord(4, "Lisa", "Simpson");
|
||||
insertPersonRecord(5, "Maggie", "Simpson");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static class OrderPreInsertCustomizer extends AbstractPreInsertCustomizer
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public List<QRecord> apply(List<QRecord> records) throws QException
|
||||
{
|
||||
for(QRecord record : records)
|
||||
{
|
||||
for(QRecord orderLine : CollectionUtils.nonNullList(record.getAssociatedRecords().get("orderLines")))
|
||||
{
|
||||
if(orderLine.getValueInteger("quantity") != null && orderLine.getValueInteger("quantity") <= 0)
|
||||
{
|
||||
record.addError(new BadInputStatusMessage("Quantity may not be less than 0. See SKU " + orderLine.getValueString("sku")));
|
||||
}
|
||||
}
|
||||
|
||||
if("throw".equals(record.getValueString("orderNo")))
|
||||
{
|
||||
throw (new QException("Throwing error, as requested..."));
|
||||
}
|
||||
}
|
||||
|
||||
return (records);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -684,6 +684,35 @@ class QJavalinApiHandlerTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testInsertErrorsFromCustomizer() throws QException
|
||||
{
|
||||
HttpResponse<String> response = Unirest.post(BASE_URL + "/api/" + VERSION + "/order/")
|
||||
.body("""
|
||||
{"orderNo": "ORD123", "storeId": 47, "orderLines":
|
||||
[
|
||||
{"lineNumber": 1, "sku": "BASIC1", "quantity": 0},
|
||||
]
|
||||
}
|
||||
""")
|
||||
.asString();
|
||||
System.out.println(response.getBody());
|
||||
assertErrorResponse(HttpStatus.BAD_REQUEST_400, "Quantity may not be less than 0", response);
|
||||
|
||||
response = Unirest.post(BASE_URL + "/api/" + VERSION + "/order/")
|
||||
.body("""
|
||||
{"orderNo": "throw", "storeId": 47}
|
||||
""")
|
||||
.asString();
|
||||
System.out.println(response.getBody());
|
||||
assertErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, "Throwing error, as requested", response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user