From b2c706270975d06ae9380e41fd9e37f65da9a1f1 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 9 May 2023 08:49:46 -0500 Subject: [PATCH] Convert QRecord errors and warnings to new QStatusMessage type hierarchy. --- .../AbstractPreInsertCustomizer.java | 3 +- .../ChildInserterPostInsertCustomizer.java | 6 +- .../core/actions/tables/DeleteAction.java | 8 +- .../core/actions/tables/InsertAction.java | 10 ++- .../core/actions/tables/UpdateAction.java | 15 ++-- .../ValidateRecordSecurityLockHelper.java | 9 ++- .../actions/values/ValueBehaviorApplier.java | 3 +- .../qqq/backend/core/model/data/QRecord.java | 31 ++++---- .../statusmessages/BadInputStatusMessage.java | 41 ++++++++++ .../statusmessages/NotFoundStatusMessage.java | 41 ++++++++++ .../PermissionDeniedMessage.java | 41 ++++++++++ .../model/statusmessages/QErrorMessage.java | 46 ++++++++++++ .../model/statusmessages/QStatusMessage.java | 74 +++++++++++++++++++ .../model/statusmessages/QWarningMessage.java | 43 +++++++++++ .../SystemErrorStatusMessage.java | 41 ++++++++++ .../AbstractPostDeleteCustomizerTest.java | 5 +- .../AbstractPostUpdateCustomizerTest.java | 7 +- .../AbstractPreDeleteCustomizerTest.java | 10 ++- .../AbstractPreUpdateCustomizerTest.java | 5 +- .../core/actions/tables/DeleteActionTest.java | 10 +-- .../core/actions/tables/InsertActionTest.java | 62 ++++++++-------- .../core/actions/tables/UpdateActionTest.java | 24 +++--- .../module/api/actions/BaseAPIActionUtil.java | 7 +- .../rdbms/actions/RDBMSDeleteAction.java | 3 +- .../rdbms/actions/RDBMSUpdateActionTest.java | 6 +- .../qqq/api/actions/ApiImplementation.java | 67 ++++++++++------- .../java/com/kingsrook/qqq/api/TestUtils.java | 38 +++++++++- .../api/javalin/QJavalinApiHandlerTest.java | 29 ++++++++ 28 files changed, 555 insertions(+), 130 deletions(-) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/BadInputStatusMessage.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/NotFoundStatusMessage.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/PermissionDeniedMessage.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QErrorMessage.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QStatusMessage.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QWarningMessage.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/SystemErrorStatusMessage.java diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreInsertCustomizer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreInsertCustomizer.java index daf89cb0..5704cdc9 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreInsertCustomizer.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreInsertCustomizer.java @@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.actions.customizers; import java.util.List; +import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.data.QRecord; @@ -50,7 +51,7 @@ public abstract class AbstractPreInsertCustomizer /******************************************************************************* ** *******************************************************************************/ - public abstract List apply(List records); + public abstract List apply(List records) throws QException; diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/ChildInserterPostInsertCustomizer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/ChildInserterPostInsertCustomizer.java index c8192088..bb370aa0 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/ChildInserterPostInsertCustomizer.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/ChildInserterPostInsertCustomizer.java @@ -34,6 +34,8 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +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; @@ -142,9 +144,9 @@ public abstract class ChildInserterPostInsertCustomizer extends AbstractPostInse QRecord childRecord = insertedRecordIterator.next(); if(CollectionUtils.nullSafeHasContents(childRecord.getErrors())) { - for(String childWarning : childRecord.getErrors()) + for(QStatusMessage error : childRecord.getErrors()) { - record.addWarning("Error creating child " + childTable.getLabel() + " (" + childWarning + ")"); + record.addWarning(new QWarningMessage("Error creating child " + childTable.getLabel() + " (" + error.toString() + ")")); } rs.add(record); continue; diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteAction.java index 8717a9a3..f8138030 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteAction.java @@ -54,6 +54,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; 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.statusmessages.NotFoundStatusMessage; +import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; @@ -68,8 +70,6 @@ public class DeleteAction { private static final QLogger LOG = QLogger.getLogger(DeleteAction.class); - public static final String NOT_FOUND_ERROR_PREFIX = "No record was found to delete"; - /******************************************************************************* @@ -238,7 +238,7 @@ public class DeleteAction { for(QRecord record : recordsForCustomizer) { - record.addWarning("An error occurred after the delete: " + e.getMessage()); + record.addWarning(new QWarningMessage("An error occurred after the delete: " + e.getMessage())); outputRecordsWithWarnings.add(record); } } @@ -400,7 +400,7 @@ public class DeleteAction QRecord recordWithError = new QRecord(); recordsWithErrors.add(recordWithError); recordWithError.setValue(primaryKeyField.getName(), primaryKeyValue); - recordWithError.addError(NOT_FOUND_ERROR_PREFIX + " for " + primaryKeyField.getLabel() + " = " + primaryKeyValue); + recordWithError.addError(new NotFoundStatusMessage("No record was found to delete for " + primaryKeyField.getLabel() + " = " + primaryKeyValue)); primaryKeysToRemoveFromInput.add(primaryKeyValue); } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/InsertAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/InsertAction.java index fd19ba27..eebdc8c4 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/InsertAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/InsertAction.java @@ -58,6 +58,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.QBackendModuleDispatcher; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; @@ -122,7 +124,7 @@ public class InsertAction extends AbstractQActionFunction errors = insertOutput.getRecords().stream().flatMap(r -> r.getErrors().stream()).toList(); + List errors = insertOutput.getRecords().stream().flatMap(r -> r.getErrors().stream().map(Object::toString)).toList(); if(CollectionUtils.nullSafeHasContents(errors)) { LOG.warn("Errors in insertAction", logPair("tableName", table.getName()), logPair("errorCount", errors.size()), errors.size() < 10 ? logPair("errors", errors) : logPair("first10Errors", errors.subList(0, 10))); @@ -160,7 +162,7 @@ public class InsertAction extends AbstractQActionFunction> keyValues = UniqueKeyHelper.getKeyValues(table, uniqueKey, record); if(keyValues.isPresent() && (existingKeys.get(uniqueKey).contains(keyValues.get()) || keysInThisList.get(uniqueKey).contains(keyValues.get()))) { - record.addError("Another record already exists with this " + uniqueKey.getDescription(table)); + record.addError(new BadInputStatusMessage("Another record already exists with this " + uniqueKey.getDescription(table))); foundDupe = true; break; } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateAction.java index 0598f57c..f6da6666 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateAction.java @@ -62,6 +62,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn; 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.statusmessages.BadInputStatusMessage; +import com.kingsrook.qqq.backend.core.model.statusmessages.NotFoundStatusMessage; +import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; @@ -77,8 +80,6 @@ public class UpdateAction { private static final QLogger LOG = QLogger.getLogger(UpdateAction.class); - public static final String NOT_FOUND_ERROR_PREFIX = "No record was found to update"; - /******************************************************************************* @@ -137,7 +138,7 @@ public class UpdateAction ////////////////////////////// // log if there were errors // ////////////////////////////// - List errors = updateOutput.getRecords().stream().flatMap(r -> r.getErrors().stream()).toList(); + List errors = updateOutput.getRecords().stream().flatMap(r -> r.getErrors().stream().map(Object::toString)).toList(); if(CollectionUtils.nullSafeHasContents(errors)) { LOG.warn("Errors in updateAction", logPair("tableName", updateInput.getTableName()), logPair("errorCount", errors.size()), errors.size() < 10 ? logPair("errors", errors) : logPair("first10Errors", errors.subList(0, 10))); @@ -180,7 +181,7 @@ public class UpdateAction { for(QRecord record : updateOutput.getRecords()) { - record.addWarning("An error occurred after the update: " + e.getMessage()); + record.addWarning(new QWarningMessage("An error occurred after the update: " + e.getMessage())); } } } @@ -228,7 +229,7 @@ public class UpdateAction //////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(record.getValue(table.getPrimaryKeyField()) == null) { - record.addError("Missing value in primary key field"); + record.addError(new BadInputStatusMessage("Missing value in primary key field")); } } } @@ -288,7 +289,7 @@ public class UpdateAction if(!lookedUpRecords.containsKey(value)) { - record.addError(NOT_FOUND_ERROR_PREFIX + " for " + primaryKeyField.getLabel() + " = " + value); + record.addError(new NotFoundStatusMessage("No record was found to update for " + primaryKeyField.getLabel() + " = " + value)); } } } @@ -319,7 +320,7 @@ public class UpdateAction { if(record.getValue(requiredField.getName()) == null || (requiredField.getType().isStringLike() && record.getValueString(requiredField.getName()).trim().equals(""))) { - record.addError("Missing value in required field: " + requiredField.getLabel()); + record.addError(new BadInputStatusMessage("Missing value in required field: " + requiredField.getLabel())); } } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ValidateRecordSecurityLockHelper.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ValidateRecordSecurityLockHelper.java index ae44f8fe..bcc18c3e 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ValidateRecordSecurityLockHelper.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/ValidateRecordSecurityLockHelper.java @@ -45,6 +45,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData; import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType; import com.kingsrook.qqq.backend.core.model.metadata.security.RecordSecurityLock; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.statusmessages.PermissionDeniedMessage; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.ListingHash; import com.kingsrook.qqq.backend.core.utils.StringUtils; @@ -225,7 +226,7 @@ public class ValidateRecordSecurityLockHelper { if(RecordSecurityLock.NullValueBehavior.DENY.equals(recordSecurityLock.getNullValueBehavior())) { - inputRecord.addError("You do not have permission to " + action.name().toLowerCase() + " this record - the referenced " + leftMostJoinTable.getLabel() + " was not found."); + inputRecord.addError(new PermissionDeniedMessage("You do not have permission to " + action.name().toLowerCase() + " this record - the referenced " + leftMostJoinTable.getLabel() + " was not found.")); } } } @@ -287,7 +288,7 @@ public class ValidateRecordSecurityLockHelper if(RecordSecurityLock.NullValueBehavior.DENY.equals(recordSecurityLock.getNullValueBehavior())) { String lockLabel = CollectionUtils.nullSafeHasContents(recordSecurityLock.getJoinNameChain()) ? recordSecurityLock.getSecurityKeyType() : table.getField(recordSecurityLock.getFieldName()).getLabel(); - record.addError("You do not have permission to " + action.name().toLowerCase() + " a record without a value in the field: " + lockLabel); + record.addError(new PermissionDeniedMessage("You do not have permission to " + action.name().toLowerCase() + " a record without a value in the field: " + lockLabel)); } } else @@ -299,12 +300,12 @@ public class ValidateRecordSecurityLockHelper /////////////////////////////////////////////////////////////////////////////////////////////// // avoid telling the user a value from a foreign record that they didn't pass in themselves. // /////////////////////////////////////////////////////////////////////////////////////////////// - record.addError("You do not have permission to " + action.name().toLowerCase() + " this record."); + record.addError(new PermissionDeniedMessage("You do not have permission to " + action.name().toLowerCase() + " this record.")); } else { QFieldMetaData field = table.getField(recordSecurityLock.getFieldName()); - record.addError("You do not have permission to " + action.name().toLowerCase() + " a record with a value of " + recordSecurityValue + " in the field: " + field.getLabel()); + record.addError(new PermissionDeniedMessage("You do not have permission to " + action.name().toLowerCase() + " a record with a value of " + recordSecurityValue + " in the field: " + field.getLabel())); } } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/ValueBehaviorApplier.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/ValueBehaviorApplier.java index 6c46113d..4e89af6e 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/ValueBehaviorApplier.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/ValueBehaviorApplier.java @@ -29,6 +29,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior; 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.utils.StringUtils; @@ -76,7 +77,7 @@ public class ValueBehaviorApplier { case TRUNCATE -> record.setValue(fieldName, StringUtils.safeTruncate(value, field.getMaxLength())); case TRUNCATE_ELLIPSIS -> record.setValue(fieldName, StringUtils.safeTruncate(value, field.getMaxLength(), "...")); - case ERROR -> record.addError("The value for " + field.getLabel() + " is too long (max allowed length=" + field.getMaxLength() + ")"); + case ERROR -> record.addError(new BadInputStatusMessage("The value for " + field.getLabel() + " is too long (max allowed length=" + field.getMaxLength() + ")")); case PASS_THROUGH -> { } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java index 00fbeb47..71f0e669 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/data/QRecord.java @@ -35,6 +35,8 @@ import java.util.Map; import com.kingsrook.qqq.backend.core.exceptions.QException; 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.QErrorMessage; +import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage; import com.kingsrook.qqq.backend.core.utils.ValueUtils; import org.apache.commons.lang.SerializationUtils; @@ -54,7 +56,8 @@ import org.apache.commons.lang.SerializationUtils; ** ** Errors are meant to hold information about things that went wrong when ** processing a record - e.g., in a list of records that may be the output of an - ** action, like a bulk load. TODO - redo as some status object? + ** action, like a bulk load. Warnings play a similar role, but are just advice + ** - they don't mean that the action was failed, just something you may need to know. *******************************************************************************/ public class QRecord implements Serializable { @@ -64,8 +67,9 @@ public class QRecord implements Serializable private Map values = new LinkedHashMap<>(); private Map displayValues = new LinkedHashMap<>(); private Map backendDetails = new LinkedHashMap<>(); - private List errors = new ArrayList<>(); - private List warnings = new ArrayList<>(); + + private List errors = new ArrayList<>(); + private List warnings = new ArrayList<>(); private Map> associatedRecords = new HashMap<>(); @@ -106,6 +110,7 @@ public class QRecord implements Serializable this.displayValues = doDeepCopy(record.displayValues); this.backendDetails = doDeepCopy(record.backendDetails); this.errors = doDeepCopy(record.errors); + this.warnings = doDeepCopy(record.warnings); this.associatedRecords = doDeepCopy(record.associatedRecords); } @@ -123,7 +128,7 @@ public class QRecord implements Serializable /******************************************************************************* - ** + ** todo - move to a cloning utils maybe? *******************************************************************************/ @SuppressWarnings({ "unchecked" }) private Map doDeepCopy(Map map) @@ -144,7 +149,7 @@ public class QRecord implements Serializable /******************************************************************************* - ** + ** todo - move to a cloning utils maybe? *******************************************************************************/ @SuppressWarnings({ "unchecked" }) private List doDeepCopy(List list) @@ -542,7 +547,7 @@ public class QRecord implements Serializable ** Getter for errors ** *******************************************************************************/ - public List getErrors() + public List getErrors() { return (errors); } @@ -553,7 +558,7 @@ public class QRecord implements Serializable ** Setter for errors ** *******************************************************************************/ - public void setErrors(List errors) + public void setErrors(List errors) { this.errors = errors; } @@ -564,7 +569,7 @@ public class QRecord implements Serializable ** Add one error to this record ** *******************************************************************************/ - public void addError(String error) + public void addError(QErrorMessage error) { this.errors.add(error); } @@ -575,7 +580,7 @@ public class QRecord implements Serializable ** Fluently Add one error to this record ** *******************************************************************************/ - public QRecord withError(String error) + public QRecord withError(QErrorMessage error) { addError(error); return (this); @@ -658,7 +663,7 @@ public class QRecord implements Serializable /******************************************************************************* ** Getter for warnings *******************************************************************************/ - public List getWarnings() + public List getWarnings() { return (this.warnings); } @@ -668,7 +673,7 @@ public class QRecord implements Serializable /******************************************************************************* ** Setter for warnings *******************************************************************************/ - public void setWarnings(List warnings) + public void setWarnings(List warnings) { this.warnings = warnings; } @@ -678,7 +683,7 @@ public class QRecord implements Serializable /******************************************************************************* ** Fluent setter for warnings *******************************************************************************/ - public QRecord withWarnings(List warnings) + public QRecord withWarnings(List warnings) { this.warnings = warnings; return (this); @@ -690,7 +695,7 @@ public class QRecord implements Serializable ** Add one warning to this record ** *******************************************************************************/ - public void addWarning(String warning) + public void addWarning(QWarningMessage warning) { this.warnings.add(warning); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/BadInputStatusMessage.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/BadInputStatusMessage.java new file mode 100644 index 00000000..124936e4 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/BadInputStatusMessage.java @@ -0,0 +1,41 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.statusmessages; + + +/******************************************************************************* + ** Record error message for when some bad input caused the issue (e.g., a missing + ** value, or an illegal value). e.g., http 400 style. + *******************************************************************************/ +public class BadInputStatusMessage extends QErrorMessage +{ + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public BadInputStatusMessage(String message) + { + super(message); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/NotFoundStatusMessage.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/NotFoundStatusMessage.java new file mode 100644 index 00000000..c1e7d67a --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/NotFoundStatusMessage.java @@ -0,0 +1,41 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.statusmessages; + + +/******************************************************************************* + ** Record error message for when something couldn't be found (e.g., a request + ** to update a record, but it isn't in the backend). + *******************************************************************************/ +public class NotFoundStatusMessage extends QErrorMessage +{ + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public NotFoundStatusMessage(String message) + { + super(message); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/PermissionDeniedMessage.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/PermissionDeniedMessage.java new file mode 100644 index 00000000..ab400bdf --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/PermissionDeniedMessage.java @@ -0,0 +1,41 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.statusmessages; + + +/******************************************************************************* + ** Record error message for when the user didn't have permission to do what they + ** were trying. + *******************************************************************************/ +public class PermissionDeniedMessage extends QErrorMessage +{ + + /******************************************************************************* + ** Constructor + ** + ******************************************************************************/ + public PermissionDeniedMessage(String message) + { + super(message); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QErrorMessage.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QErrorMessage.java new file mode 100644 index 00000000..10fc371b --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QErrorMessage.java @@ -0,0 +1,46 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.statusmessages; + + +/******************************************************************************* + ** Abstract base class for all errors to be attached to QRecords. + ** + ** Framework is aware of a few specific sultypes here, that drive things like + ** returning http 400 vs 500. + ** + ** Applications can define further subtypes (recommended to subclass this class's + ** children, rather than this class), to help give (type-based) definition to errors. + *******************************************************************************/ +public abstract class QErrorMessage extends QStatusMessage +{ + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public QErrorMessage(String message) + { + super(message); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QStatusMessage.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QStatusMessage.java new file mode 100644 index 00000000..b146a68e --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QStatusMessage.java @@ -0,0 +1,74 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.statusmessages; + + +import java.io.Serializable; + + +/******************************************************************************* + ** Abstract Base class for status messages (errors or warnings) that can be + ** attached to QRecords. + ** + ** They look like exceptions, but they aren't throwable, and they are meant + ** to just be put in a record's error or warning list. Those lists were originally + ** just Strings, but we wanted to have some type information communicated with + ** them, e.g., for marking an error as caused by bad-data (e.g., from a user, e.g., + ** for an HTTP 400) vs. a server-side error, etc. + *******************************************************************************/ +public abstract class QStatusMessage implements Serializable +{ + private String message; + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public QStatusMessage(String message) + { + this.message = message; + } + + + + /******************************************************************************* + ** Getter for message + ** + *******************************************************************************/ + public String getMessage() + { + return message; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public String toString() + { + return (message); + } +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QWarningMessage.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QWarningMessage.java new file mode 100644 index 00000000..497db0bf --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/QWarningMessage.java @@ -0,0 +1,43 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.statusmessages; + + +/******************************************************************************* + ** Class to wrap warning messages to attach to QRecords. + ** + ** Applications can define subtypes as needed, to help give (type-based) + ** definition to warnings. + *******************************************************************************/ +public class QWarningMessage extends QStatusMessage +{ + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public QWarningMessage(String message) + { + super(message); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/SystemErrorStatusMessage.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/SystemErrorStatusMessage.java new file mode 100644 index 00000000..6de5433d --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/statusmessages/SystemErrorStatusMessage.java @@ -0,0 +1,41 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.core.model.statusmessages; + + +/******************************************************************************* + ** Record error message for when the system was at fault - not the user. e.g., + ** http 500 style. + *******************************************************************************/ +public class SystemErrorStatusMessage extends QErrorMessage +{ + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public SystemErrorStatusMessage(String message) + { + super(message); + } + +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostDeleteCustomizerTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostDeleteCustomizerTest.java index 411b671d..b4817cd1 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostDeleteCustomizerTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostDeleteCustomizerTest.java @@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage; import com.kingsrook.qqq.backend.core.utils.TestUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -74,7 +75,7 @@ class AbstractPostDeleteCustomizerTest extends BaseTest assertEquals(1, deleteOutput.getRecordsWithWarnings().size()); assertEquals(1, deleteOutput.getRecordsWithWarnings().get(0).getValue("id")); assertEquals(2, deleteOutput.getDeletedRecordCount()); - assertEquals("You shouldn't have deleted Homer...", deleteOutput.getRecordsWithWarnings().get(0).getWarnings().get(0)); + assertEquals("You shouldn't have deleted Homer...", deleteOutput.getRecordsWithWarnings().get(0).getWarnings().get(0).getMessage()); GetInput getInput = new GetInput(); getInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); @@ -107,7 +108,7 @@ class AbstractPostDeleteCustomizerTest extends BaseTest { if(record.getValue("firstName").equals("Homer")) { - record.addWarning("You shouldn't have deleted Homer..."); + record.addWarning(new QWarningMessage("You shouldn't have deleted Homer...")); } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostUpdateCustomizerTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostUpdateCustomizerTest.java index faa63377..3b5e15f2 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostUpdateCustomizerTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostUpdateCustomizerTest.java @@ -42,6 +42,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.TestUtils; import org.junit.jupiter.api.Test; @@ -110,7 +111,7 @@ class AbstractPostUpdateCustomizerTest extends BaseTest updateInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("firstName", "Warning"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); assertTrue(CollectionUtils.nullSafeIsEmpty(updateOutput.getRecords().get(0).getErrors())); - assertTrue(updateOutput.getRecords().get(0).getWarnings().stream().anyMatch(s -> s.contains("updated to a warning value"))); + assertTrue(updateOutput.getRecords().get(0).getWarnings().stream().anyMatch(s -> s.getMessage().contains("updated to a warning value"))); GetInput getInput = new GetInput(); getInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); @@ -128,7 +129,7 @@ class AbstractPostUpdateCustomizerTest extends BaseTest updateInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("firstName", "throw"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); assertTrue(CollectionUtils.nullSafeIsEmpty(updateOutput.getRecords().get(0).getErrors())); - assertTrue(updateOutput.getRecords().get(0).getWarnings().stream().anyMatch(s -> s.contains("Forced Exception"))); + assertTrue(updateOutput.getRecords().get(0).getWarnings().stream().anyMatch(s -> s.getMessage().contains("Forced Exception"))); GetInput getInput = new GetInput(); getInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); @@ -178,7 +179,7 @@ class AbstractPostUpdateCustomizerTest extends BaseTest if("warning".equalsIgnoreCase(record.getValueString("firstName"))) { - record.addWarning("Record was updated to a warning value"); + record.addWarning(new QWarningMessage("Record was updated to a warning value")); } if("throw".equalsIgnoreCase(record.getValueString("firstName"))) diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreDeleteCustomizerTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreDeleteCustomizerTest.java index 03c049fd..d021d3a8 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreDeleteCustomizerTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreDeleteCustomizerTest.java @@ -35,6 +35,8 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; 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.QWarningMessage; import com.kingsrook.qqq.backend.core.utils.TestUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -74,7 +76,7 @@ class AbstractPreDeleteCustomizerTest extends BaseTest assertEquals(0, deleteOutput.getRecordsWithWarnings().size()); assertEquals(1, deleteOutput.getRecordsWithErrors().get(0).getValue("id")); assertEquals(1, deleteOutput.getDeletedRecordCount()); - assertEquals("You may not delete a Homer.", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0)); + assertEquals("You may not delete a Homer.", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0).getMessage()); GetInput getInput = new GetInput(); getInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); @@ -99,7 +101,7 @@ class AbstractPreDeleteCustomizerTest extends BaseTest assertEquals(1, deleteOutput.getRecordsWithWarnings().size()); assertEquals(3, deleteOutput.getRecordsWithWarnings().get(0).getValue("id")); assertEquals(1, deleteOutput.getDeletedRecordCount()); - assertEquals("It was a bad idea to delete Bart", deleteOutput.getRecordsWithWarnings().get(0).getWarnings().get(0)); + assertEquals("It was a bad idea to delete Bart", deleteOutput.getRecordsWithWarnings().get(0).getWarnings().get(0).getMessage()); GetInput getInput = new GetInput(); getInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); @@ -127,11 +129,11 @@ class AbstractPreDeleteCustomizerTest extends BaseTest { if(record.getValue("firstName").equals("Homer")) { - record.addError("You may not delete a Homer."); + record.addError(new BadInputStatusMessage("You may not delete a Homer.")); } else if(record.getValue("firstName").equals("Bart")) { - record.addWarning("It was a bad idea to delete Bart"); + record.addWarning(new QWarningMessage("It was a bad idea to delete Bart")); } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreUpdateCustomizerTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreUpdateCustomizerTest.java index cc26afe8..04b2e35c 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreUpdateCustomizerTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPreUpdateCustomizerTest.java @@ -35,6 +35,7 @@ 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.code.QCodeReference; 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.utils.TestUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -70,7 +71,7 @@ class AbstractPreUpdateCustomizerTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); updateInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("firstName", "--"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertTrue(updateOutput.getRecords().get(0).getErrors().stream().anyMatch(s -> s.contains("must contain at least one letter"))); + assertTrue(updateOutput.getRecords().get(0).getErrors().stream().anyMatch(s -> s.getMessage().contains("must contain at least one letter"))); GetInput getInput = new GetInput(); getInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); @@ -146,7 +147,7 @@ class AbstractPreUpdateCustomizerTest extends BaseTest //////////////////////////////////////////////////////////////// if(!record.getValueString("firstName").matches(".*\\w.*")) { - record.addError("First name must contain at least one letter."); + record.addError(new BadInputStatusMessage("First name must contain at least one letter.")); } ////////////////////////////////////////////////////////////// diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteActionTest.java index 3c9b2bec..8492eff3 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/DeleteActionTest.java @@ -76,7 +76,7 @@ class DeleteActionTest extends BaseTest assertEquals(1, result.getDeletedRecordCount()); assertEquals(1, result.getRecordsWithErrors().size()); assertEquals(2, result.getRecordsWithErrors().get(0).getValueInteger("id")); - assertEquals("No record was found to delete for Id = 2", result.getRecordsWithErrors().get(0).getErrors().get(0)); + assertEquals("No record was found to delete for Id = 2", result.getRecordsWithErrors().get(0).getErrors().get(0).getMessage()); } @@ -331,28 +331,28 @@ class DeleteActionTest extends BaseTest DeleteOutput deleteOutput = new DeleteAction().execute(deleteInput); assertEquals(0, deleteOutput.getDeletedRecordCount()); assertEquals(1, deleteOutput.getRecordsWithErrors().size()); - assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0)); + assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0).getMessage()); deleteInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM); deleteInput.setPrimaryKeys(List.of(1)); deleteOutput = new DeleteAction().execute(deleteInput); assertEquals(0, deleteOutput.getDeletedRecordCount()); assertEquals(1, deleteOutput.getRecordsWithErrors().size()); - assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0)); + assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0).getMessage()); deleteInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC); deleteInput.setPrimaryKeys(List.of(1)); deleteOutput = new DeleteAction().execute(deleteInput); assertEquals(0, deleteOutput.getDeletedRecordCount()); assertEquals(1, deleteOutput.getRecordsWithErrors().size()); - assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0)); + assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0).getMessage()); deleteInput.setTableName(TestUtils.TABLE_NAME_ORDER_EXTRINSIC); deleteInput.setPrimaryKeys(List.of(1)); deleteOutput = new DeleteAction().execute(deleteInput); assertEquals(0, deleteOutput.getDeletedRecordCount()); assertEquals(1, deleteOutput.getRecordsWithErrors().size()); - assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0)); + assertEquals("No record was found to delete for Id = 1", deleteOutput.getRecordsWithErrors().get(0).getErrors().get(0).getMessage()); } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/InsertActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/InsertActionTest.java index 6d903b78..6b98b801 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/InsertActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/InsertActionTest.java @@ -113,7 +113,7 @@ class InsertActionTest extends BaseTest assertEquals(1, TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_PERSON_MEMORY).size()); assertNull(insertOutput.getRecords().get(0).getValueInteger("id")); assertEquals(1, insertOutput.getRecords().get(0).getErrors().size()); - assertThat(insertOutput.getRecords().get(0).getErrors().get(0)).contains("Another record already exists with this First Name and Last Name"); + assertThat(insertOutput.getRecords().get(0).getErrors().get(0).getMessage()).contains("Another record already exists with this First Name and Last Name"); ////////////////////////////////////////////////////////////////////////////////////////// // try to insert that person again, with 2 others - the 2 should work, but the one fail // @@ -156,7 +156,7 @@ class InsertActionTest extends BaseTest assertEquals(1, insertOutput.getRecords().get(0).getValueInteger("id")); assertNull(insertOutput.getRecords().get(1).getValueInteger("id")); assertEquals(1, insertOutput.getRecords().get(1).getErrors().size()); - assertThat(insertOutput.getRecords().get(1).getErrors().get(0)).contains("Another record already exists with this First Name and Last Name"); + assertThat(insertOutput.getRecords().get(1).getErrors().get(0).getMessage()).contains("Another record already exists with this First Name and Last Name"); } @@ -183,7 +183,7 @@ class InsertActionTest extends BaseTest assertEquals(1, insertOutput.getRecords().get(0).getValueInteger("id")); assertNull(insertOutput.getRecords().get(1).getValueInteger("id")); assertEquals(1, insertOutput.getRecords().get(1).getErrors().size()); - assertThat(insertOutput.getRecords().get(1).getErrors().get(0)).contains("Another record already exists with this Name"); + assertThat(insertOutput.getRecords().get(1).getErrors().get(0).getMessage()).contains("Another record already exists with this Name"); } @@ -303,7 +303,7 @@ class InsertActionTest extends BaseTest insertInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC); insertInput.setRecords(List.of(new QRecord().withValue("lineItemId", null).withValue("key", "kidsCanCallYou").withValue("value", "HoJu"))); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -314,7 +314,7 @@ class InsertActionTest extends BaseTest insertInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC); insertInput.setRecords(List.of(new QRecord().withValue("lineItemId", 1701).withValue("key", "kidsCanCallYou").withValue("value", "HoJu"))); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); } { @@ -341,7 +341,7 @@ class InsertActionTest extends BaseTest insertLineItemExtrinsicInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC); insertLineItemExtrinsicInput.setRecords(List.of(new QRecord().withValue("lineItemId", 4200).withValue("key", "kidsCanCallYou").withValue("value", "HoJu"))); InsertOutput insertLineItemExtrinsicOutput = new InsertAction().execute(insertLineItemExtrinsicInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertLineItemExtrinsicOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertLineItemExtrinsicOutput.getRecords().get(0).getErrors().get(0).getMessage()); } { @@ -371,9 +371,9 @@ class InsertActionTest extends BaseTest new QRecord().withValue("lineItemId", 4700).withValue("key", "theKidsCanCallYou").withValue("value", "HoJu") )); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0).getMessage()); assertEquals(0, insertOutput.getRecords().get(3).getErrors().size()); assertNotNull(insertOutput.getRecords().get(3).getValueInteger("id")); } @@ -395,14 +395,14 @@ class InsertActionTest extends BaseTest new QRecord().withValue("lineItemId", 4700).withValue("key", "theKidsCanCallYou").withValue("value", "HoJu") )); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0).getMessage()); assertEquals(0, insertOutput.getRecords().get(3).getErrors().size()); assertNotNull(insertOutput.getRecords().get(3).getValueInteger("id")); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(4).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(5).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(6).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(4).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(5).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(6).getErrors().get(0).getMessage()); assertEquals(0, insertOutput.getRecords().get(7).getErrors().size()); assertNotNull(insertOutput.getRecords().get(7).getValueInteger("id")); } @@ -426,7 +426,7 @@ class InsertActionTest extends BaseTest insertInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM); insertInput.setRecords(List.of(new QRecord().withValue("orderId", null).withValue("sku", "BASIC1").withValue("quantity", 1))); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -437,7 +437,7 @@ class InsertActionTest extends BaseTest insertInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM); insertInput.setRecords(List.of(new QRecord().withValue("orderId", 1701).withValue("sku", "BASIC1").withValue("quantity", 1))); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); } { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -457,7 +457,7 @@ class InsertActionTest extends BaseTest insertLineItemInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM); insertLineItemInput.setRecords(List.of(new QRecord().withValue("orderId", 42).withValue("sku", "BASIC1").withValue("quantity", 1))); InsertOutput insertLineItemOutput = new InsertAction().execute(insertLineItemInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertLineItemOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertLineItemOutput.getRecords().get(0).getErrors().get(0).getMessage()); } { @@ -480,9 +480,9 @@ class InsertActionTest extends BaseTest new QRecord().withValue("orderId", 47).withValue("sku", "BASIC1").withValue("quantity", 1) )); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0).getMessage()); assertEquals(0, insertOutput.getRecords().get(3).getErrors().size()); assertNotNull(insertOutput.getRecords().get(3).getValueInteger("id")); } @@ -504,14 +504,14 @@ class InsertActionTest extends BaseTest new QRecord().withValue("orderId", 47).withValue("sku", "BASIC1").withValue("quantity", 1) )); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(1).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(2).getErrors().get(0).getMessage()); assertEquals(0, insertOutput.getRecords().get(3).getErrors().size()); assertNotNull(insertOutput.getRecords().get(3).getValueInteger("id")); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(4).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(5).getErrors().get(0)); - assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(6).getErrors().get(0)); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(4).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(5).getErrors().get(0).getMessage()); + assertEquals("You do not have permission to insert this record - the referenced Order was not found.", insertOutput.getRecords().get(6).getErrors().get(0).getMessage()); assertEquals(0, insertOutput.getRecords().get(7).getErrors().size()); assertNotNull(insertOutput.getRecords().get(7).getValueInteger("id")); } @@ -531,7 +531,7 @@ class InsertActionTest extends BaseTest insertInput.setTableName(TestUtils.TABLE_NAME_ORDER); insertInput.setRecords(List.of(new QRecord().withValue("storeId", 2))); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert a record with a value of 2 in the field: Store Id", insertOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert a record with a value of 2 in the field: Store Id", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); assertEquals(0, TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER).size()); } @@ -549,7 +549,7 @@ class InsertActionTest extends BaseTest insertInput.setTableName(TestUtils.TABLE_NAME_ORDER); insertInput.setRecords(List.of(new QRecord())); InsertOutput insertOutput = new InsertAction().execute(insertInput); - assertEquals("You do not have permission to insert a record without a value in the field: Store Id", insertOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to insert a record without a value in the field: Store Id", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); assertEquals(0, TestUtils.queryTable(qInstance, TestUtils.TABLE_NAME_ORDER).size()); } @@ -617,7 +617,7 @@ class InsertActionTest extends BaseTest // 1st record had no value in orderNo - assert it errored // //////////////////////////////////////////////////////////// assertEquals(1, insertOutput.getRecords().get(0).getErrors().size()); - assertEquals("Missing value in required field: Order No", insertOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("Missing value in required field: Order No", insertOutput.getRecords().get(0).getErrors().get(0).getMessage()); /////////////////////////////////////////////// // 2nd record had a value - it should insert // @@ -629,7 +629,7 @@ class InsertActionTest extends BaseTest // 3rd record had spaces-only in orderNo - make sure that fails // ////////////////////////////////////////////////////////////////// assertEquals(1, insertOutput.getRecords().get(2).getErrors().size()); - assertEquals("Missing value in required field: Order No", insertOutput.getRecords().get(2).getErrors().get(0)); + assertEquals("Missing value in required field: Order No", insertOutput.getRecords().get(2).getErrors().get(0).getMessage()); } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateActionTest.java index 6b522bc9..27efa736 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/tables/UpdateActionTest.java @@ -376,7 +376,7 @@ class UpdateActionTest extends BaseTest // 1st record tried to set a null orderNo - assert it errored // //////////////////////////////////////////////////////////////// assertEquals(1, updateOutput.getRecords().get(0).getErrors().size()); - assertEquals("Missing value in required field: Order No", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("Missing value in required field: Order No", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); //////////////////////////////////////////////////////////////// // 2nd record didn't try to change orderNo, so should be fine // @@ -392,7 +392,7 @@ class UpdateActionTest extends BaseTest // 4th record tried to set orderNo to all spaces - assert it errored // /////////////////////////////////////////////////////////////////////// assertEquals(1, updateOutput.getRecords().get(3).getErrors().size()); - assertEquals("Missing value in required field: Order No", updateOutput.getRecords().get(3).getErrors().get(0)); + assertEquals("Missing value in required field: Order No", updateOutput.getRecords().get(3).getErrors().get(0).getMessage()); } @@ -439,7 +439,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM); updateInput.setRecords(List.of(new QRecord().withValue("id", 10).withValue("orderId", null).withValue("sku", "BASIC2"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } //////////////////////////////////////////////////////////////////////////////////// @@ -452,7 +452,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM); updateInput.setRecords(List.of(new QRecord().withValue("id", 20).withValue("sku", "BASIC3"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("No record was found to update for Id = 20", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("No record was found to update for Id = 20", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -464,7 +464,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM); updateInput.setRecords(List.of(new QRecord().withValue("id", 10).withValue("orderId", 2).withValue("sku", "BASIC3"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } /////////////////////////////////////////////////////////// @@ -475,7 +475,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC); updateInput.setRecords(List.of(new QRecord().withValue("id", 100).withValue("lineItemId", null).withValue("key", "updatedKey"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } ////////////////////////////////////////////////////////////////////////////////////////////// @@ -488,7 +488,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC); updateInput.setRecords(List.of(new QRecord().withValue("id", 200).withValue("key", "updatedKey"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("No record was found to update for Id = 200", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("No record was found to update for Id = 200", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -500,7 +500,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_LINE_ITEM_EXTRINSIC); updateInput.setRecords(List.of(new QRecord().withValue("id", 100).withValue("lineItemId", 20).withValue("key", "updatedKey"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to update this record - the referenced Order was not found.", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } } @@ -518,7 +518,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_ORDER); updateInput.setRecords(List.of(new QRecord().withValue("id", 999).withValue("orderNo", "updated"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("No record was found to update for Id = 999", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("No record was found to update for Id = 999", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } @@ -548,7 +548,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_ORDER); updateInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("orderNo", "updated"))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("No record was found to update for Id = 1", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("No record was found to update for Id = 1", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); QContext.getQSession().withSecurityKeyValues(MapBuilder.of(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, ListBuilder.of(true))); assertThat(TestUtils.queryTable(TestUtils.TABLE_NAME_ORDER)).noneMatch(r -> r.getValueString("orderNo").equals("updated")); @@ -562,7 +562,7 @@ class UpdateActionTest extends BaseTest updateInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("orderNo", "updated").withValue("storeId", 2))); updateOutput = new UpdateAction().execute(updateInput); - assertEquals("You do not have permission to update a record with a value of 2 in the field: Store Id", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to update a record with a value of 2 in the field: Store Id", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); QContext.getQSession().withSecurityKeyValues(MapBuilder.of(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, ListBuilder.of(true))); assertThat(TestUtils.queryTable(TestUtils.TABLE_NAME_ORDER)).noneMatch(r -> r.getValueString("orderNo").equals("updated")); @@ -593,7 +593,7 @@ class UpdateActionTest extends BaseTest updateInput.setTableName(TestUtils.TABLE_NAME_ORDER); updateInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("storeId", null))); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); - assertEquals("You do not have permission to update a record without a value in the field: Store Id", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("You do not have permission to update a record without a value in the field: Store Id", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); assertEquals(0, TestUtils.queryTable(TestUtils.TABLE_NAME_ORDER).stream().filter(r -> r.getValue("storeId") == null).count()); } diff --git a/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java b/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java index c2617519..5666c27f 100644 --- a/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java +++ b/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/actions/BaseAPIActionUtil.java @@ -55,6 +55,7 @@ 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.session.QSession; +import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.backend.core.utils.SleepUtils; @@ -202,7 +203,7 @@ public class BaseAPIActionUtil } catch(Exception e) { - record.addError("Error: " + e.getMessage()); + record.addError(new SystemErrorStatusMessage("Error: " + e.getMessage())); insertOutput.addRecord(record); } @@ -421,13 +422,13 @@ public class BaseAPIActionUtil JSONObject errorObject = jsonObject.getJSONObject("error"); if(errorObject.has("message")) { - record.addError("Error: " + errorObject.getString("message")); + record.addError(new SystemErrorStatusMessage("Error: " + errorObject.getString("message"))); } } if(CollectionUtils.nullSafeIsEmpty(record.getErrors())) { - record.addError("Unspecified error executing insert."); + record.addError(new SystemErrorStatusMessage("Unspecified error executing insert.")); } } diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java index 02dd90ed..b98e4b77 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSDeleteAction.java @@ -37,6 +37,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.JoinsContext; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage; import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager; @@ -217,7 +218,7 @@ public class RDBMSDeleteAction extends AbstractRDBMSAction implements DeleteInte catch(Exception e) { LOG.debug("Exception trying to delete [" + tableName + "][" + primaryKey + "]", e); - deleteOutput.addRecordWithError(new QRecord(table, primaryKey).withError("Record was not deleted: " + e.getMessage())); + deleteOutput.addRecordWithError(new QRecord(table, primaryKey).withError(new SystemErrorStatusMessage("Record was not deleted: " + e.getMessage()))); } } diff --git a/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSUpdateActionTest.java b/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSUpdateActionTest.java index b75c2417..a024b1dc 100644 --- a/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSUpdateActionTest.java +++ b/qqq-backend-module-rdbms/src/test/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSUpdateActionTest.java @@ -365,7 +365,7 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest updateInput.setRecords(records); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); assertFalse(updateOutput.getRecords().get(0).getErrors().isEmpty()); - assertEquals("Missing value in primary key field", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("Missing value in primary key field", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } { @@ -377,7 +377,7 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest updateInput.setRecords(records); UpdateOutput updateOutput = new UpdateAction().execute(updateInput); assertFalse(updateOutput.getRecords().get(0).getErrors().isEmpty()); - assertEquals("Missing value in primary key field", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("Missing value in primary key field", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); } { @@ -393,7 +393,7 @@ public class RDBMSUpdateActionTest extends RDBMSActionTest UpdateOutput updateOutput = new UpdateAction().execute(updateInput); assertFalse(updateOutput.getRecords().get(0).getErrors().isEmpty()); - assertEquals("Missing value in primary key field", updateOutput.getRecords().get(0).getErrors().get(0)); + assertEquals("Missing value in primary key field", updateOutput.getRecords().get(0).getErrors().get(0).getMessage()); assertTrue(updateOutput.getRecords().get(1).getErrors().isEmpty()); diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java index 675d37b8..603f5e1e 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java @@ -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 errors = insertOutput.getRecords().get(0).getErrors(); + List 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 outputRecord = new LinkedHashMap<>(); outputRecord.put(table.getPrimaryKeyField(), insertOutput.getRecords().get(0).getValue(table.getPrimaryKeyField())); - List warnings = insertOutput.getRecords().get(0).getWarnings(); + List 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 outputRecord = new LinkedHashMap<>(); response.add(outputRecord); - List errors = record.getErrors(); - List warnings = record.getWarnings(); + List errors = record.getErrors(); + List 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 errors = updateOutput.getRecords().get(0).getErrors(); + List 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 errors = record.getErrors(); + List 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 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> response = new ArrayList<>(); - List recordsWithErrors = deleteOutput.getRecordsWithErrors(); - Map> primaryKeyToErrorsMap = new HashMap<>(); + List recordsWithErrors = deleteOutput.getRecordsWithErrors(); + Map> 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 errors = primaryKeyToErrorsMap.get(primaryKeyString); + String primaryKeyString = ValueUtils.getValueAsString(primaryKey); + List 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 errors) + { + return StringUtils.joinWithCommasAndAnd(errors.stream().map(QStatusMessage::getMessage).toList()); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -1109,13 +1126,9 @@ public class ApiImplementation /******************************************************************************* ** *******************************************************************************/ - private static boolean areAnyErrorsBadRequest(List errors) + private static boolean areAnyErrorsBadRequest(List 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 errors) + private static boolean areAnyErrorsNotFound(List 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)); } } diff --git a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/TestUtils.java b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/TestUtils.java index 91061612..4926b5a1 100644 --- a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/TestUtils.java +++ b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/TestUtils.java @@ -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 apply(List 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); + } + } } diff --git a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/javalin/QJavalinApiHandlerTest.java b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/javalin/QJavalinApiHandlerTest.java index 34832bdb..2f43f7dc 100644 --- a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/javalin/QJavalinApiHandlerTest.java +++ b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/javalin/QJavalinApiHandlerTest.java @@ -684,6 +684,35 @@ class QJavalinApiHandlerTest extends BaseTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testInsertErrorsFromCustomizer() throws QException + { + HttpResponse 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); + } + + + /******************************************************************************* ** *******************************************************************************/