mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Add instance-level pre- and post- insert and update table customizers
This commit is contained in:
@ -54,6 +54,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||||
|
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.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||||
@ -174,9 +175,21 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
|
|||||||
.withRecordList(insertOutput.getRecords()));
|
.withRecordList(insertOutput.getRecords()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
// finally, run the post-insert customizer, if there is one //
|
// finally, run the post-insert customizers, if there are any //
|
||||||
//////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
runPostInsertCustomizers(insertInput, table, insertOutput);
|
||||||
|
|
||||||
|
return insertOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
private static void runPostInsertCustomizers(InsertInput insertInput, QTableMetaData table, InsertOutput insertOutput)
|
||||||
|
{
|
||||||
Optional<TableCustomizerInterface> postInsertCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.POST_INSERT_RECORD.getRole());
|
Optional<TableCustomizerInterface> postInsertCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.POST_INSERT_RECORD.getRole());
|
||||||
if(postInsertCustomizer.isPresent())
|
if(postInsertCustomizer.isPresent())
|
||||||
{
|
{
|
||||||
@ -193,7 +206,25 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return insertOutput;
|
///////////////////////////////////////////////
|
||||||
|
// run all of the instance-level customizers //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
List<QCodeReference> tableCustomizerCodes = QContext.getQInstance().getTableCustomizers(TableCustomizers.POST_INSERT_RECORD);
|
||||||
|
for(QCodeReference tableCustomizerCode : tableCustomizerCodes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TableCustomizerInterface tableCustomizer = QCodeLoader.getAdHoc(TableCustomizerInterface.class, tableCustomizerCode);
|
||||||
|
insertOutput.setRecords(tableCustomizer.postInsert(insertInput, insertOutput.getRecords()));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
for(QRecord record : insertOutput.getRecords())
|
||||||
|
{
|
||||||
|
record.addWarning(new QWarningMessage("An error occurred after the insert: " + e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -308,6 +339,19 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
|
|||||||
insertInput.setRecords(preInsertCustomizer.get().preInsert(insertInput, insertInput.getRecords(), isPreview));
|
insertInput.setRecords(preInsertCustomizer.get().preInsert(insertInput, insertInput.getRecords(), isPreview));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// run all of the instance-level customizers //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
List<QCodeReference> tableCustomizerCodes = QContext.getQInstance().getTableCustomizers(TableCustomizers.PRE_INSERT_RECORD);
|
||||||
|
for(QCodeReference tableCustomizerCode : tableCustomizerCodes)
|
||||||
|
{
|
||||||
|
TableCustomizerInterface tableCustomizer = QCodeLoader.getAdHoc(TableCustomizerInterface.class, tableCustomizerCode);
|
||||||
|
if(whenToRun.equals(tableCustomizer.whenToRunPreInsert(insertInput, isPreview)))
|
||||||
|
{
|
||||||
|
insertInput.setRecords(tableCustomizer.preInsert(insertInput, insertInput.getRecords(), isPreview));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
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.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DynamicDefaultValueBehavior;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.DynamicDefaultValueBehavior;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldBehavior;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldBehavior;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
@ -199,6 +200,18 @@ public class UpdateAction
|
|||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
// finally, run the post-update customizer, if there is one //
|
// finally, run the post-update customizer, if there is one //
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
runPostUpdateCustomizers(updateInput, table, updateOutput, oldRecordList);
|
||||||
|
|
||||||
|
return updateOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
private static void runPostUpdateCustomizers(UpdateInput updateInput, QTableMetaData table, UpdateOutput updateOutput, Optional<List<QRecord>> oldRecordList)
|
||||||
|
{
|
||||||
Optional<TableCustomizerInterface> postUpdateCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.POST_UPDATE_RECORD.getRole());
|
Optional<TableCustomizerInterface> postUpdateCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.POST_UPDATE_RECORD.getRole());
|
||||||
if(postUpdateCustomizer.isPresent())
|
if(postUpdateCustomizer.isPresent())
|
||||||
{
|
{
|
||||||
@ -215,7 +228,49 @@ public class UpdateAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateOutput;
|
///////////////////////////////////////////////
|
||||||
|
// run all of the instance-level customizers //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
List<QCodeReference> tableCustomizerCodes = QContext.getQInstance().getTableCustomizers(TableCustomizers.POST_UPDATE_RECORD);
|
||||||
|
for(QCodeReference tableCustomizerCode : tableCustomizerCodes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TableCustomizerInterface tableCustomizer = QCodeLoader.getAdHoc(TableCustomizerInterface.class, tableCustomizerCode);
|
||||||
|
updateOutput.setRecords(tableCustomizer.postUpdate(updateInput, updateOutput.getRecords(), oldRecordList));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
for(QRecord record : updateOutput.getRecords())
|
||||||
|
{
|
||||||
|
record.addWarning(new QWarningMessage("An error occurred after the update: " + e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
private static void runPreUpdateCustomizers(UpdateInput updateInput, QTableMetaData table, Optional<List<QRecord>> oldRecordList, boolean isPreview) throws QException
|
||||||
|
{
|
||||||
|
Optional<TableCustomizerInterface> preUpdateCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.PRE_UPDATE_RECORD.getRole());
|
||||||
|
if(preUpdateCustomizer.isPresent())
|
||||||
|
{
|
||||||
|
updateInput.setRecords(preUpdateCustomizer.get().preUpdate(updateInput, updateInput.getRecords(), isPreview, oldRecordList));
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// run all of the instance-level customizers //
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
List<QCodeReference> tableCustomizerCodes = QContext.getQInstance().getTableCustomizers(TableCustomizers.PRE_UPDATE_RECORD);
|
||||||
|
for(QCodeReference tableCustomizerCode : tableCustomizerCodes)
|
||||||
|
{
|
||||||
|
TableCustomizerInterface tableCustomizer = QCodeLoader.getAdHoc(TableCustomizerInterface.class, tableCustomizerCode);
|
||||||
|
updateInput.setRecords(tableCustomizer.preUpdate(updateInput, updateInput.getRecords(), isPreview, oldRecordList));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -278,11 +333,7 @@ public class UpdateAction
|
|||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// after all validations, run the pre-update customizer, if there is one //
|
// after all validations, run the pre-update customizer, if there is one //
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
Optional<TableCustomizerInterface> preUpdateCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.PRE_UPDATE_RECORD.getRole());
|
runPreUpdateCustomizers(updateInput, table, oldRecordList, isPreview);
|
||||||
if(preUpdateCustomizer.isPresent())
|
|
||||||
{
|
|
||||||
updateInput.setRecords(preUpdateCustomizer.get().preUpdate(updateInput, updateInput.getRecords(), isPreview, oldRecordList));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ import java.util.function.Supplier;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationHandler;
|
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationHandler;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizerInterface;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
|
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
|
||||||
import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph;
|
import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph;
|
||||||
@ -252,6 +253,17 @@ public class QInstanceValidator
|
|||||||
{
|
{
|
||||||
validateSimpleCodeReference("Instance metaDataActionCustomizer ", qInstance.getMetaDataActionCustomizer(), MetaDataActionCustomizerInterface.class);
|
validateSimpleCodeReference("Instance metaDataActionCustomizer ", qInstance.getMetaDataActionCustomizer(), MetaDataActionCustomizerInterface.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(qInstance.getTableCustomizers() != null)
|
||||||
|
{
|
||||||
|
for(Map.Entry<String, List<QCodeReference>> entry : qInstance.getTableCustomizers().entrySet())
|
||||||
|
{
|
||||||
|
for(QCodeReference codeReference : CollectionUtils.nonNullList(entry.getValue()))
|
||||||
|
{
|
||||||
|
validateSimpleCodeReference("Instance tableCustomizer of type " + entry.getKey() + ": ", codeReference, TableCustomizerInterface.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -301,6 +313,17 @@ public class QInstanceValidator
|
|||||||
validatorPlugins.clear();
|
validatorPlugins.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for validatorPlugins
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static ListingHash<Class<?>, QInstanceValidatorPluginInterface<?>> getValidatorPlugins()
|
||||||
|
{
|
||||||
|
return validatorPlugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -2238,8 +2261,7 @@ public class QInstanceValidator
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@SafeVarargs
|
public void validateSimpleCodeReference(String prefix, QCodeReference codeReference, Class<?>... anyOfExpectedClasses)
|
||||||
private void validateSimpleCodeReference(String prefix, QCodeReference codeReference, Class<?>... anyOfExpectedClasses)
|
|
||||||
{
|
{
|
||||||
if(!preAssertionsForCodeReference(codeReference, prefix))
|
if(!preAssertionsForCodeReference(codeReference, prefix))
|
||||||
{
|
{
|
||||||
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@ -30,6 +31,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||||
import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph;
|
import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph;
|
||||||
import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction;
|
import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
@ -65,6 +67,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.security.QSecurityKeyType;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.scheduler.schedulable.SchedulableType;
|
import com.kingsrook.qqq.backend.core.scheduler.schedulable.SchedulableType;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ListingHash;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
import io.github.cdimascio.dotenv.Dotenv;
|
import io.github.cdimascio.dotenv.Dotenv;
|
||||||
import io.github.cdimascio.dotenv.DotenvEntry;
|
import io.github.cdimascio.dotenv.DotenvEntry;
|
||||||
@ -116,6 +119,8 @@ public class QInstance
|
|||||||
private QPermissionRules defaultPermissionRules = QPermissionRules.defaultInstance();
|
private QPermissionRules defaultPermissionRules = QPermissionRules.defaultInstance();
|
||||||
private QAuditRules defaultAuditRules = QAuditRules.defaultInstanceLevelNone();
|
private QAuditRules defaultAuditRules = QAuditRules.defaultInstanceLevelNone();
|
||||||
|
|
||||||
|
private ListingHash<String, QCodeReference> tableCustomizers;
|
||||||
|
|
||||||
@Deprecated(since = "migrated to metaDataCustomizer")
|
@Deprecated(since = "migrated to metaDataCustomizer")
|
||||||
private QCodeReference metaDataFilter = null;
|
private QCodeReference metaDataFilter = null;
|
||||||
|
|
||||||
@ -1623,4 +1628,76 @@ public class QInstance
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for tableCustomizers
|
||||||
|
*******************************************************************************/
|
||||||
|
public ListingHash<String, QCodeReference> getTableCustomizers()
|
||||||
|
{
|
||||||
|
return (this.tableCustomizers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for tableCustomizers
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setTableCustomizers(ListingHash<String, QCodeReference> tableCustomizers)
|
||||||
|
{
|
||||||
|
this.tableCustomizers = tableCustomizers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for tableCustomizers
|
||||||
|
*******************************************************************************/
|
||||||
|
public QInstance withTableCustomizers(ListingHash<String, QCodeReference> tableCustomizers)
|
||||||
|
{
|
||||||
|
this.tableCustomizers = tableCustomizers;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QInstance withTableCustomizer(String role, QCodeReference customizer)
|
||||||
|
{
|
||||||
|
if(this.tableCustomizers == null)
|
||||||
|
{
|
||||||
|
this.tableCustomizers = new ListingHash<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tableCustomizers.add(role, customizer);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QInstance withTableCustomizer(TableCustomizers tableCustomizer, QCodeReference customizer)
|
||||||
|
{
|
||||||
|
return (withTableCustomizer(tableCustomizer.getRole(), customizer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for tableCustomizers
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QCodeReference> getTableCustomizers(TableCustomizers tableCustomizer)
|
||||||
|
{
|
||||||
|
if(this.tableCustomizers == null)
|
||||||
|
{
|
||||||
|
return (Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.tableCustomizers.getOrDefault(tableCustomizer.getRole(), Collections.emptyList()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.tables;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizerInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
|
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.statusmessages.SystemErrorStatusMessage;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ListingHash;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class InsertActionInstanceLevelTableCustomizersTest
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testInstanceLevelCustomizers() throws QException
|
||||||
|
{
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.PRE_INSERT_RECORD, new QCodeReference(BreaksEverythingCustomizer.class));
|
||||||
|
QRecord record = new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("name", "octogon"))).getRecords().get(0);
|
||||||
|
assertEquals("Everything is broken", record.getErrorsAsString());
|
||||||
|
assertNull(record.getValueInteger("id"));
|
||||||
|
|
||||||
|
QContext.getQInstance().setTableCustomizers(new ListingHash<>());
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.PRE_INSERT_RECORD, new QCodeReference(SetsFirstName.class));
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.PRE_INSERT_RECORD, new QCodeReference(SetsLastName.class));
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.POST_INSERT_RECORD, new QCodeReference(DoesNothing.class));
|
||||||
|
DoesNothing.callCount = 0;
|
||||||
|
record = new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("name", "octogon"))).getRecords().get(0);
|
||||||
|
assertEquals("Jeff", record.getValueString("firstName"));
|
||||||
|
assertEquals("Smith", record.getValueString("lastName"));
|
||||||
|
assertNotNull(record.getValueInteger("id"));
|
||||||
|
assertEquals(1, DoesNothing.callCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static class BreaksEverythingCustomizer implements TableCustomizerInterface
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public List<QRecord> preInsertOrUpdate(AbstractActionInput input, List<QRecord> records, boolean isPreview, Optional<List<QRecord>> oldRecordList) throws QException
|
||||||
|
{
|
||||||
|
records.forEach(r -> r.addError(new SystemErrorStatusMessage("Everything is broken")));
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static class SetsFirstName implements TableCustomizerInterface
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public List<QRecord> preInsertOrUpdate(AbstractActionInput input, List<QRecord> records, boolean isPreview, Optional<List<QRecord>> oldRecordList) throws QException
|
||||||
|
{
|
||||||
|
records.forEach(r -> r.setValue("firstName", "Jeff"));
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static class SetsLastName implements TableCustomizerInterface
|
||||||
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public List<QRecord> preInsertOrUpdate(AbstractActionInput input, List<QRecord> records, boolean isPreview, Optional<List<QRecord>> oldRecordList) throws QException
|
||||||
|
{
|
||||||
|
records.forEach(r -> r.setValue("lastName", "Smith"));
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static class DoesNothing implements TableCustomizerInterface
|
||||||
|
{
|
||||||
|
static int callCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public List<QRecord> postInsertOrUpdate(AbstractActionInput input, List<QRecord> records, Optional<List<QRecord>> oldRecordList) throws QException
|
||||||
|
{
|
||||||
|
callCount++;
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2025. 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.tables;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||||
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
|
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.actions.tables.update.UpdateInput;
|
||||||
|
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.utils.ListingHash;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class UpdateActionInstanceLevelTableCustomizersTest extends BaseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testInstanceLevelCustomizers() throws QException
|
||||||
|
{
|
||||||
|
QRecord record = new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("name", "octogon"))).getRecords().get(0);
|
||||||
|
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.PRE_UPDATE_RECORD, new QCodeReference(InsertActionInstanceLevelTableCustomizersTest.BreaksEverythingCustomizer.class));
|
||||||
|
record = new UpdateAction().execute(new UpdateInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("id", record.getValue("id")).withValue("name", "octogon"))).getRecords().get(0);
|
||||||
|
assertEquals("Everything is broken", record.getErrorsAsString());
|
||||||
|
|
||||||
|
QContext.getQInstance().setTableCustomizers(new ListingHash<>());
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.PRE_UPDATE_RECORD, new QCodeReference(InsertActionInstanceLevelTableCustomizersTest.SetsFirstName.class));
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.PRE_UPDATE_RECORD, new QCodeReference(InsertActionInstanceLevelTableCustomizersTest.SetsLastName.class));
|
||||||
|
QContext.getQInstance().withTableCustomizer(TableCustomizers.POST_UPDATE_RECORD, new QCodeReference(InsertActionInstanceLevelTableCustomizersTest.DoesNothing.class));
|
||||||
|
InsertActionInstanceLevelTableCustomizersTest.DoesNothing.callCount = 0;
|
||||||
|
record = new UpdateAction().execute(new UpdateInput(TestUtils.TABLE_NAME_SHAPE).withRecord(new QRecord().withValue("id", record.getValue("id")).withValue("name", "octogon"))).getRecords().get(0);
|
||||||
|
assertEquals("Jeff", record.getValueString("firstName"));
|
||||||
|
assertEquals("Smith", record.getValueString("lastName"));
|
||||||
|
assertNotNull(record.getValueInteger("id"));
|
||||||
|
assertEquals(1, InsertActionInstanceLevelTableCustomizersTest.DoesNothing.callCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -176,6 +176,30 @@ public class QInstanceValidatorTest extends BaseTest
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testInstanceLevelTableCustomizers()
|
||||||
|
{
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.withTableCustomizer(TableCustomizers.PRE_INSERT_RECORD, new QCodeReference(QInstanceValidator.class)),
|
||||||
|
"Instance tableCustomizer of type preInsertRecord: CodeReference is not of the expected type");
|
||||||
|
|
||||||
|
assertValidationFailureReasons((qInstance) ->
|
||||||
|
{
|
||||||
|
qInstance.withTableCustomizer(TableCustomizers.POST_UPDATE_RECORD, new QCodeReference(QInstanceValidator.class));
|
||||||
|
qInstance.withTableCustomizer(TableCustomizers.POST_UPDATE_RECORD, new QCodeReference(QInstanceValidator.class));
|
||||||
|
qInstance.withTableCustomizer(TableCustomizers.PRE_DELETE_RECORD, new QCodeReference(QInstanceValidator.class));
|
||||||
|
},
|
||||||
|
"Instance tableCustomizer of type postUpdateRecord: CodeReference is not of the expected type",
|
||||||
|
"Instance tableCustomizer of type postUpdateRecord: CodeReference is not of the expected type",
|
||||||
|
"Instance tableCustomizer of type preDeleteRecord: CodeReference is not of the expected type");
|
||||||
|
|
||||||
|
assertValidationSuccess((qInstance) -> qInstance.withTableCustomizer(TableCustomizers.POST_UPDATE_RECORD, new QCodeReference(CustomizerValid.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Test an instance with null backends - should throw.
|
** Test an instance with null backends - should throw.
|
||||||
**
|
**
|
||||||
|
Reference in New Issue
Block a user