mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Adding maxLength to fields, along with initial version of FieldBehviors and ValueBehaviorApplier, including ValueTooLongBehavior
This commit is contained in:
@ -22,11 +22,14 @@
|
|||||||
package com.kingsrook.qqq.backend.core.actions.dashboard;
|
package com.kingsrook.qqq.backend.core.actions.dashboard;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
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.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
|
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +40,7 @@ import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
|||||||
public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -104,7 +108,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
protected String linkTableBulkLoad(RenderWidgetInput input, String tableName) throws QException
|
public static String linkTableBulkLoad(RenderWidgetInput input, String tableName) throws QException
|
||||||
{
|
{
|
||||||
String tablePath = input.getInstance().getTablePath(input, tableName);
|
String tablePath = input.getInstance().getTablePath(input, tableName);
|
||||||
return (tablePath + "/" + tableName + ".bulkInsert");
|
return (tablePath + "/" + tableName + ".bulkInsert");
|
||||||
@ -115,10 +119,34 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
protected String linkTableFilter(RenderWidgetInput input, String tableName, QQueryFilter filter) throws QException
|
public static String linkTableFilter(RenderWidgetInput input, String tableName, QQueryFilter filter) throws QException
|
||||||
{
|
{
|
||||||
String tablePath = input.getInstance().getTablePath(input, tableName);
|
String tablePath = input.getInstance().getTablePath(input, tableName);
|
||||||
return (tablePath + "?filter=" + URLEncoder.encode(JsonUtils.toJson(filter), Charset.defaultCharset()));
|
return (tablePath + "?filter=" + URLEncoder.encode(JsonUtils.toJson(filter), Charset.defaultCharset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static String linkRecordEdit(AbstractActionInput input, String tableName, Serializable recordId) throws QException
|
||||||
|
{
|
||||||
|
String tablePath = input.getInstance().getTablePath(input, tableName);
|
||||||
|
return (tablePath + "/" + recordId + "/edit");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static String linkProcessForRecord(AbstractActionInput input, String processName, Serializable recordId) throws QException
|
||||||
|
{
|
||||||
|
QProcessMetaData process = input.getInstance().getProcess(processName);
|
||||||
|
String tableName = process.getTableName();
|
||||||
|
String tablePath = input.getInstance().getTablePath(input, tableName);
|
||||||
|
return (tablePath + "/" + recordId + "/" + processName);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.values.ValueBehaviorApplier;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
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.insert.InsertInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||||
@ -55,6 +56,9 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
|
|||||||
ActionHelper.validateSession(insertInput);
|
ActionHelper.validateSession(insertInput);
|
||||||
setAutomationStatusField(insertInput);
|
setAutomationStatusField(insertInput);
|
||||||
|
|
||||||
|
ValueBehaviorApplier.applyFieldBehaviors(insertInput.getInstance(), insertInput.getTable(), insertInput.getRecords());
|
||||||
|
// todo - need to handle records with errors coming out of here...
|
||||||
|
|
||||||
QBackendModuleInterface qModule = getBackendModuleInterface(insertInput);
|
QBackendModuleInterface qModule = getBackendModuleInterface(insertInput);
|
||||||
// todo pre-customization - just get to modify the request?
|
// todo pre-customization - just get to modify the request?
|
||||||
InsertOutput insertOutput = qModule.getInsertInterface().execute(insertInput);
|
InsertOutput insertOutput = qModule.getInsertInterface().execute(insertInput);
|
||||||
|
@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.actions.tables;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
||||||
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.values.ValueBehaviorApplier;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
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;
|
||||||
@ -46,6 +47,9 @@ public class UpdateAction
|
|||||||
ActionHelper.validateSession(updateInput);
|
ActionHelper.validateSession(updateInput);
|
||||||
setAutomationStatusField(updateInput);
|
setAutomationStatusField(updateInput);
|
||||||
|
|
||||||
|
ValueBehaviorApplier.applyFieldBehaviors(updateInput.getInstance(), updateInput.getTable(), updateInput.getRecords());
|
||||||
|
// todo - need to handle records with errors coming out of here...
|
||||||
|
|
||||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(updateInput.getBackend());
|
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(updateInput.getBackend());
|
||||||
// todo pre-customization - just get to modify the request?
|
// todo pre-customization - just get to modify the request?
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.values;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
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.utils.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Utility class to apply value behaviors to records.
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ValueBehaviorApplier
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void applyFieldBehaviors(QInstance instance, QTableMetaData table, List<QRecord> recordList)
|
||||||
|
{
|
||||||
|
for(QFieldMetaData field : table.getFields().values())
|
||||||
|
{
|
||||||
|
String fieldName = field.getName();
|
||||||
|
if(field.getType().equals(QFieldType.STRING) && field.getMaxLength() != null)
|
||||||
|
{
|
||||||
|
applyValueTooLongBehavior(instance, recordList, field, fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void applyValueTooLongBehavior(QInstance instance, List<QRecord> recordList, QFieldMetaData field, String fieldName)
|
||||||
|
{
|
||||||
|
ValueTooLongBehavior valueTooLongBehavior = field.getBehavior(instance, ValueTooLongBehavior.class);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// don't process PASS_THROUGH - so we don't have to iterate over the whole record list to do noop //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(valueTooLongBehavior != null && !valueTooLongBehavior.equals(ValueTooLongBehavior.PASS_THROUGH))
|
||||||
|
{
|
||||||
|
for(QRecord record : recordList)
|
||||||
|
{
|
||||||
|
String value = record.getValueString(fieldName);
|
||||||
|
if(value != null && value.length() > field.getMaxLength())
|
||||||
|
{
|
||||||
|
switch(valueTooLongBehavior)
|
||||||
|
{
|
||||||
|
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 PASS_THROUGH ->
|
||||||
|
{
|
||||||
|
}
|
||||||
|
default -> throw new IllegalStateException("Unexpected valueTooLongBehavior: " + valueTooLongBehavior);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,6 +26,7 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -67,6 +68,16 @@ public @interface QField
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
String possibleValueSourceName() default "";
|
String possibleValueSourceName() default "";
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
int maxLength() default Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
ValueTooLongBehavior valueTooLongBehavior() default ValueTooLongBehavior.PASS_THROUGH;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// new attributes here likely need implementation in QFieldMetaData.constructFromGetter //
|
// new attributes here likely need implementation in QFieldMetaData.constructFromGetter //
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.model.metadata.fields;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public interface FieldBehavior
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -25,12 +25,16 @@ package com.kingsrook.qqq.backend.core.model.metadata.fields;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import com.github.hervian.reflection.Fun;
|
import com.github.hervian.reflection.Fun;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
@ -56,6 +60,19 @@ public class QFieldMetaData implements Cloneable
|
|||||||
private Serializable defaultValue;
|
private Serializable defaultValue;
|
||||||
private String possibleValueSourceName;
|
private String possibleValueSourceName;
|
||||||
|
|
||||||
|
private Integer maxLength;
|
||||||
|
private Set<FieldBehavior> behaviors;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// w/ longer-term vision: //
|
||||||
|
// - more enums that implement ValueTooLongBehavior e.g., NumberOutsideRangeBehavior or DecimalPrecisionErrorBehavior //
|
||||||
|
// - QInstance.Set<FieldBehavior> defaultFieldBehaviors //
|
||||||
|
// - QBackendMetaData.Set<FieldBehavior> defaultFieldBehaviors //
|
||||||
|
// - QTableMetaData.Set<FieldBehavior> defaultFieldBehaviors //
|
||||||
|
// - inherit behaviors all the way down (up?) //
|
||||||
|
// - instance validation to make sure you don’t specify more than 1 behavior of a given type at a given level. //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private List<FieldAdornment> adornments;
|
private List<FieldAdornment> adornments;
|
||||||
|
|
||||||
|
|
||||||
@ -176,6 +193,16 @@ public class QFieldMetaData implements Cloneable
|
|||||||
{
|
{
|
||||||
setPossibleValueSourceName(fieldAnnotation.possibleValueSourceName());
|
setPossibleValueSourceName(fieldAnnotation.possibleValueSourceName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(fieldAnnotation.maxLength() != Integer.MAX_VALUE)
|
||||||
|
{
|
||||||
|
setMaxLength(fieldAnnotation.maxLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fieldAnnotation.valueTooLongBehavior() != ValueTooLongBehavior.PASS_THROUGH)
|
||||||
|
{
|
||||||
|
withBehavior(fieldAnnotation.valueTooLongBehavior());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(QException qe)
|
catch(QException qe)
|
||||||
@ -532,4 +559,118 @@ public class QFieldMetaData implements Cloneable
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for maxLength
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getMaxLength()
|
||||||
|
{
|
||||||
|
return maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for maxLength
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setMaxLength(Integer maxLength)
|
||||||
|
{
|
||||||
|
this.maxLength = maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for maxLength
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldMetaData withMaxLength(Integer maxLength)
|
||||||
|
{
|
||||||
|
this.maxLength = maxLength;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for behaviors
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Set<FieldBehavior> getBehaviors()
|
||||||
|
{
|
||||||
|
return behaviors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public <T extends FieldBehavior> T getBehavior(QInstance instance, Class<T> behaviorType)
|
||||||
|
{
|
||||||
|
for(FieldBehavior fieldBehavior : CollectionUtils.nonNullCollection(behaviors))
|
||||||
|
{
|
||||||
|
if(behaviorType.isInstance(fieldBehavior))
|
||||||
|
{
|
||||||
|
return (behaviorType.cast(fieldBehavior));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// todo - cascade/inherit behaviors down from table, backend, instance //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// return default behavior for this type //
|
||||||
|
///////////////////////////////////////////
|
||||||
|
if(behaviorType.equals(ValueTooLongBehavior.class))
|
||||||
|
{
|
||||||
|
return behaviorType.cast(ValueTooLongBehavior.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for behaviors
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setBehaviors(Set<FieldBehavior> behaviors)
|
||||||
|
{
|
||||||
|
this.behaviors = behaviors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for behaviors
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldMetaData withBehaviors(Set<FieldBehavior> behaviors)
|
||||||
|
{
|
||||||
|
this.behaviors = behaviors;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for behaviors
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldMetaData withBehavior(FieldBehavior behavior)
|
||||||
|
{
|
||||||
|
if(behaviors == null)
|
||||||
|
{
|
||||||
|
behaviors = new HashSet<>();
|
||||||
|
}
|
||||||
|
this.behaviors.add(behavior);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.model.metadata.fields;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public enum ValueTooLongBehavior implements FieldBehavior
|
||||||
|
{
|
||||||
|
TRUNCATE,
|
||||||
|
TRUNCATE_ELLIPSIS,
|
||||||
|
ERROR,
|
||||||
|
PASS_THROUGH;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static FieldBehavior getDefault()
|
||||||
|
{
|
||||||
|
return PASS_THROUGH;
|
||||||
|
}
|
||||||
|
}
|
@ -28,12 +28,15 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
@ -45,6 +48,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
|||||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ListingHash;
|
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 com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -304,6 +308,41 @@ public class GeneralProcessUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Load all rows from a table, into a map, keyed by the keyFieldName - typed as
|
||||||
|
** the specified keyType.
|
||||||
|
**
|
||||||
|
** Note - null values from the key field are NOT put in the map.
|
||||||
|
**
|
||||||
|
** If multiple values are found for the key, they'll squash each other, and only
|
||||||
|
** one random value will appear.
|
||||||
|
**
|
||||||
|
** Also, note, this is inherently unsafe, if you were to call it on a table with
|
||||||
|
** too many rows... Caveat emptor.
|
||||||
|
*******************************************************************************/
|
||||||
|
public static <T extends Serializable> Map<T, QRecord> loadTableToMap(AbstractActionInput parentActionInput, String tableName, Class<T> keyType, String keyFieldName) throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = new QueryInput(parentActionInput.getInstance());
|
||||||
|
queryInput.setSession(parentActionInput.getSession());
|
||||||
|
queryInput.setTableName(tableName);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
List<QRecord> records = queryOutput.getRecords();
|
||||||
|
|
||||||
|
Map<T, QRecord> map = new HashMap<>();
|
||||||
|
for(QRecord record : records)
|
||||||
|
{
|
||||||
|
Serializable value = record.getValue(keyFieldName);
|
||||||
|
if(value != null)
|
||||||
|
{
|
||||||
|
T valueAsT = ValueUtils.getValueAsType(keyType, value);
|
||||||
|
map.put(valueAsT, record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (map);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Note - null values from the key field are NOT put in the map.
|
** Note - null values from the key field are NOT put in the map.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -406,4 +445,19 @@ public class GeneralProcessUtils
|
|||||||
return (rs);
|
return (rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static Integer count(AbstractActionInput input, String tableName, QQueryFilter filter) throws QException
|
||||||
|
{
|
||||||
|
CountInput countInput = new CountInput(input.getInstance());
|
||||||
|
countInput.setSession(input.getSession());
|
||||||
|
countInput.setTableName(tableName);
|
||||||
|
countInput.setFilter(filter);
|
||||||
|
CountOutput countOutput = new CountAction().execute(countInput);
|
||||||
|
return (countOutput.getCount());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,4 +585,51 @@ public class ValueUtils
|
|||||||
throw (new QValueException("Unsupported class " + value.getClass().getName() + " for converting to ByteArray."));
|
throw (new QValueException("Unsupported class " + value.getClass().getName() + " for converting to ByteArray."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Serializable> T getValueAsType(Class<T> type, Serializable value)
|
||||||
|
{
|
||||||
|
if(type.equals(Integer.class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsInteger(value);
|
||||||
|
}
|
||||||
|
else if(type.equals(String.class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsString(value);
|
||||||
|
}
|
||||||
|
else if(type.equals(Boolean.class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsBoolean(value);
|
||||||
|
}
|
||||||
|
else if(type.equals(BigDecimal.class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsBigDecimal(value);
|
||||||
|
}
|
||||||
|
else if(type.equals(LocalDateTime.class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsLocalDateTime(value);
|
||||||
|
}
|
||||||
|
else if(type.equals(LocalDate.class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsLocalDate(value);
|
||||||
|
}
|
||||||
|
else if(type.equals(Instant.class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsInstant(value);
|
||||||
|
}
|
||||||
|
else if(type.equals(byte[].class))
|
||||||
|
{
|
||||||
|
return (T) getValueAsByteArray(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new QValueException("Unsupported type [" + type.getSimpleName() + "] in getValueAsType.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. 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.values;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
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.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for ValueBehaviorApplier
|
||||||
|
*******************************************************************************/
|
||||||
|
class ValueBehaviorApplierTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testValueTooLongNormalCases()
|
||||||
|
{
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
QTableMetaData table = qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
table.getField("firstName").withMaxLength(10).withBehavior(ValueTooLongBehavior.TRUNCATE);
|
||||||
|
table.getField("lastName").withMaxLength(10).withBehavior(ValueTooLongBehavior.TRUNCATE_ELLIPSIS);
|
||||||
|
table.getField("email").withMaxLength(20).withBehavior(ValueTooLongBehavior.ERROR);
|
||||||
|
|
||||||
|
List<QRecord> recordList = List.of(
|
||||||
|
new QRecord().withValue("id", 1).withValue("firstName", "First name too long").withValue("lastName", "Smith").withValue("email", "john@smith.com"),
|
||||||
|
new QRecord().withValue("id", 2).withValue("firstName", "John").withValue("lastName", "Last name too long").withValue("email", "john@smith.com"),
|
||||||
|
new QRecord().withValue("id", 3).withValue("firstName", "First name too long").withValue("lastName", "Smith").withValue("email", "john.smith@emaildomainwayytolongtofit.com")
|
||||||
|
);
|
||||||
|
ValueBehaviorApplier.applyFieldBehaviors(qInstance, table, recordList);
|
||||||
|
|
||||||
|
assertEquals("First name", getRecordById(recordList, 1).getValueString("firstName"));
|
||||||
|
assertEquals("Last na...", getRecordById(recordList, 2).getValueString("lastName"));
|
||||||
|
assertEquals("john.smith@emaildomainwayytolongtofit.com", getRecordById(recordList, 3).getValueString("email"));
|
||||||
|
assertFalse(getRecordById(recordList, 3).getErrors().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testValueTooLongEdgeCases()
|
||||||
|
{
|
||||||
|
QInstance qInstance = TestUtils.defineInstance();
|
||||||
|
QTableMetaData table = qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// make sure PASS THROUGH actually does nothing, and that a maxLength w/ no behavior specified also does nothing (e.g., does PASS_THROUGH) //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
table.getField("firstName").withMaxLength(10).withBehavior(ValueTooLongBehavior.PASS_THROUGH);
|
||||||
|
table.getField("lastName").withMaxLength(10);
|
||||||
|
|
||||||
|
List<QRecord> recordList = List.of(
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
// make sure nulls and empty are okay, and don't get changed. //
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
new QRecord().withValue("id", 1).withValue("firstName", "First name too long").withValue("lastName", null).withValue("email", "john@smith.com"),
|
||||||
|
new QRecord().withValue("id", 2).withValue("firstName", "").withValue("lastName", "Last name too long").withValue("email", "john@smith.com")
|
||||||
|
);
|
||||||
|
ValueBehaviorApplier.applyFieldBehaviors(qInstance, table, recordList);
|
||||||
|
|
||||||
|
assertEquals("First name too long", getRecordById(recordList, 1).getValueString("firstName"));
|
||||||
|
assertNull(getRecordById(recordList, 1).getValueString("lastName"));
|
||||||
|
assertEquals("Last name too long", getRecordById(recordList, 2).getValueString("lastName"));
|
||||||
|
assertEquals("", getRecordById(recordList, 2).getValueString("firstName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static QRecord getRecordById(List<QRecord> recordList, Integer id)
|
||||||
|
{
|
||||||
|
Optional<QRecord> recordOpt = recordList.stream().filter(r -> r.getValueInteger("id").equals(id)).findFirst();
|
||||||
|
if(recordOpt.isEmpty())
|
||||||
|
{
|
||||||
|
fail("Didn't find record with id=" + id);
|
||||||
|
}
|
||||||
|
return (recordOpt.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,8 +22,10 @@
|
|||||||
package com.kingsrook.qqq.backend.core.utils;
|
package com.kingsrook.qqq.backend.core.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -34,6 +36,7 @@ import java.util.GregorianCalendar;
|
|||||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
@ -231,6 +234,7 @@ class ValueUtilsTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -251,4 +255,20 @@ class ValueUtilsTest
|
|||||||
assertThat(assertThrows(QValueException.class, () -> ValueUtils.getValueAsInstant(new Object())).getMessage()).contains("Unsupported class");
|
assertThat(assertThrows(QValueException.class, () -> ValueUtils.getValueAsInstant(new Object())).getMessage()).contains("Unsupported class");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testGetValueAsType()
|
||||||
|
{
|
||||||
|
assertEquals(1, ValueUtils.getValueAsType(Integer.class, "1"));
|
||||||
|
assertEquals("1", ValueUtils.getValueAsType(String.class, 1));
|
||||||
|
assertEquals(BigDecimal.ONE, ValueUtils.getValueAsType(BigDecimal.class, 1));
|
||||||
|
assertEquals(true, ValueUtils.getValueAsType(Boolean.class, "true"));
|
||||||
|
assertArrayEquals("a".getBytes(StandardCharsets.UTF_8), ValueUtils.getValueAsType(byte[].class, "a"));
|
||||||
|
assertThrows(QValueException.class, () -> ValueUtils.getValueAsType(Serializable.class, 1));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -60,18 +60,18 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.javalin</groupId>
|
<groupId>io.javalin</groupId>
|
||||||
<artifactId>javalin</artifactId>
|
<artifactId>javalin</artifactId>
|
||||||
<version>4.6.1</version>
|
<version>5.1.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.konghq</groupId>
|
<groupId>com.konghq</groupId>
|
||||||
<artifactId>unirest-java</artifactId>
|
<artifactId>unirest-java</artifactId>
|
||||||
<version>3.4.00</version>
|
<version>3.13.12</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<version>2.1.210</version>
|
<version>2.1.214</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -26,6 +26,7 @@ import java.io.File;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -286,10 +287,12 @@ public class QJavalinProcessHandler
|
|||||||
// process uploaded files //
|
// process uploaded files //
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
for(UploadedFile uploadedFile : context.uploadedFiles())
|
for(UploadedFile uploadedFile : context.uploadedFiles())
|
||||||
|
{
|
||||||
|
try(InputStream content = uploadedFile.content())
|
||||||
{
|
{
|
||||||
QUploadedFile qUploadedFile = new QUploadedFile();
|
QUploadedFile qUploadedFile = new QUploadedFile();
|
||||||
qUploadedFile.setBytes(uploadedFile.getContent().readAllBytes());
|
qUploadedFile.setBytes(content.readAllBytes());
|
||||||
qUploadedFile.setFilename(uploadedFile.getFilename());
|
qUploadedFile.setFilename(uploadedFile.filename());
|
||||||
|
|
||||||
UUIDAndTypeStateKey key = new UUIDAndTypeStateKey(StateType.UPLOADED_FILE);
|
UUIDAndTypeStateKey key = new UUIDAndTypeStateKey(StateType.UPLOADED_FILE);
|
||||||
TempFileStateProvider.getInstance().put(key, qUploadedFile);
|
TempFileStateProvider.getInstance().put(key, qUploadedFile);
|
||||||
@ -298,6 +301,7 @@ public class QJavalinProcessHandler
|
|||||||
|
|
||||||
archiveUploadedFile(runProcessInput, qUploadedFile);
|
archiveUploadedFile(runProcessInput, qUploadedFile);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
||||||
// deal with params that specify an initial-records filter //
|
// deal with params that specify an initial-records filter //
|
||||||
|
@ -25,6 +25,7 @@ package com.kingsrook.sampleapp;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
|
import io.javalin.plugin.bundled.CorsPluginConfig;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@ -66,8 +67,8 @@ public class SampleJavalinServer
|
|||||||
QJavalinImplementation qJavalinImplementation = new QJavalinImplementation(qInstance);
|
QJavalinImplementation qJavalinImplementation = new QJavalinImplementation(qInstance);
|
||||||
javalinService = Javalin.create(config ->
|
javalinService = Javalin.create(config ->
|
||||||
{
|
{
|
||||||
// todo - not all!!
|
// todo - not all?
|
||||||
config.enableCorsForAllOrigins();
|
config.plugins.enableCors(cors -> cors.add(CorsPluginConfig::anyHost));
|
||||||
}).start(PORT);
|
}).start(PORT);
|
||||||
javalinService.routes(qJavalinImplementation.getRoutes());
|
javalinService.routes(qJavalinImplementation.getRoutes());
|
||||||
|
|
||||||
@ -88,8 +89,7 @@ public class SampleJavalinServer
|
|||||||
});
|
});
|
||||||
javalinService.before(QJavalinImplementation::hotSwapQInstance);
|
javalinService.before(QJavalinImplementation::hotSwapQInstance);
|
||||||
|
|
||||||
javalinService.after(ctx ->
|
javalinService.after(ctx -> ctx.res().setHeader("Access-Control-Allow-Origin", "http://localhost:3000"));
|
||||||
ctx.res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000"));
|
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user