CE-1068: initial checkin of variables in filter handling

This commit is contained in:
Tim Chamberlain
2024-04-30 19:22:30 -05:00
parent 5c0b1ea2c3
commit 60ce1d8c09
15 changed files with 503 additions and 26 deletions

View File

@ -557,7 +557,7 @@ public class GenerateReportAction extends AbstractQActionFunction<ReportInput, R
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
private void setInputValuesInQueryFilter(ReportInput reportInput, QQueryFilter queryFilter) private void setInputValuesInQueryFilter(ReportInput reportInput, QQueryFilter queryFilter) throws QException
{ {
if(queryFilter == null || queryFilter.getCriteria() == null) if(queryFilter == null || queryFilter.getCriteria() == null)
{ {

View File

@ -25,13 +25,17 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter; import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.AbstractFilterExpression; import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.AbstractFilterExpression;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.FilterVariableExpression;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.ValueUtils; import com.kingsrook.qqq.backend.core.utils.ValueUtils;
@ -411,6 +415,83 @@ public class QQueryFilter implements Serializable, Cloneable
/*******************************************************************************
** Replaces any FilterVariables' variableNames with one constructed from the field
** name, criteria, and index, camel style
**
*******************************************************************************/
public void prepForBackend()
{
Map<String, Integer> fieldOperatorMap = new HashMap<>();
for(QFilterCriteria criterion : getCriteria())
{
if(criterion.getValues() != null)
{
int criteriaIndex = 1;
int valueIndex = 0;
for(Serializable value : criterion.getValues())
{
///////////////////////////////////////////////////////////////////////////////
// keep track of what the index is for this criterion, this way if there are //
// more than one with the same id/operator values, we can differentiate //
///////////////////////////////////////////////////////////////////////////////
String backendName = getBackendName(criterion, valueIndex);
if(!fieldOperatorMap.containsKey(backendName))
{
fieldOperatorMap.put(backendName, criteriaIndex);
}
else
{
criteriaIndex = fieldOperatorMap.get(backendName) + 1;
fieldOperatorMap.put(backendName, criteriaIndex);
}
if(value instanceof FilterVariableExpression fve)
{
if(criteriaIndex > 1)
{
backendName += criteriaIndex;
}
fve.setVariableName(backendName);
}
valueIndex++;
}
}
}
}
/*******************************************************************************
** builds up a backend name for a field variable expression
**
*******************************************************************************/
private String getBackendName(QFilterCriteria criterion, int valueIndex)
{
StringBuilder backendName = new StringBuilder(criterion.getFieldName());
for(String operatorParts : criterion.getOperator().name().split("_"))
{
backendName.append(StringUtils.ucFirst(operatorParts.toLowerCase()));
}
if(criterion.getOperator().equals(QCriteriaOperator.BETWEEN) || criterion.getOperator().equals(QCriteriaOperator.NOT_BETWEEN))
{
if(valueIndex == 0)
{
backendName.append("From");
}
else
{
backendName.append("To");
}
}
return (backendName.toString());
}
/******************************************************************************* /*******************************************************************************
** Replace any criteria values that look like ${input.XXX} with the value of XXX ** Replace any criteria values that look like ${input.XXX} with the value of XXX
** from the supplied inputValues map. ** from the supplied inputValues map.
@ -419,7 +500,7 @@ public class QQueryFilter implements Serializable, Cloneable
** QQueryFilter - e.g., if it's one that defined in metaData, and that we don't ** QQueryFilter - e.g., if it's one that defined in metaData, and that we don't
** want to be (permanently) changed!! ** want to be (permanently) changed!!
*******************************************************************************/ *******************************************************************************/
public void interpretValues(Map<String, Serializable> inputValues) public void interpretValues(Map<String, Serializable> inputValues) throws QException
{ {
QMetaDataVariableInterpreter variableInterpreter = new QMetaDataVariableInterpreter(); QMetaDataVariableInterpreter variableInterpreter = new QMetaDataVariableInterpreter();
variableInterpreter.addValueMap("input", inputValues); variableInterpreter.addValueMap("input", inputValues);
@ -433,11 +514,18 @@ public class QQueryFilter implements Serializable, Cloneable
{ {
if(value instanceof AbstractFilterExpression<?>) if(value instanceof AbstractFilterExpression<?>)
{ {
///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// todo - do we want to try to interpret values within the expression? // // if a filter variable expression, evaluate the input values, which //
// e.g., greater than now minus ${input.noOfDays} // // will replace the variables with the corresponding actual values //
///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
newValues.add(value); if(value instanceof FilterVariableExpression filterVariableExpression)
{
newValues.add(filterVariableExpression.evaluateInputValues(inputValues));
}
else
{
newValues.add(value);
}
} }
else else
{ {

View File

@ -23,6 +23,8 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
import com.kingsrook.qqq.backend.core.exceptions.QException;
/******************************************************************************* /*******************************************************************************
@ -33,7 +35,17 @@ public abstract class AbstractFilterExpression<T extends Serializable> implement
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public abstract T evaluate(); public abstract T evaluate() throws QException;
/*******************************************************************************
**
*******************************************************************************/
public T evaluateInputValues(Map<String, Serializable> inputValues) throws QException
{
return (T) this;
}

View File

@ -0,0 +1,213 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions;
import java.io.Serializable;
import java.util.Map;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
/*******************************************************************************
**
*******************************************************************************/
public class FilterVariableExpression extends AbstractFilterExpression<Serializable>
{
private String variableName;
private String fieldName;
private String operator;
private int valueIndex = 0;
/*******************************************************************************
**
*******************************************************************************/
@Override
public Serializable evaluate() throws QException
{
throw (new QUserFacingException("Missing variable value."));
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public Serializable evaluateInputValues(Map<String, Serializable> inputValues) throws QException
{
if(!inputValues.containsKey(variableName))
{
throw (new QUserFacingException("Missing variable value."));
}
return (inputValues.get(variableName));
}
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public FilterVariableExpression()
{
}
/*******************************************************************************
** Constructor
**
*******************************************************************************/
private FilterVariableExpression(String fieldName, int valueIndex)
{
this.fieldName = fieldName;
this.valueIndex = valueIndex;
}
/*******************************************************************************
** Getter for valueIndex
*******************************************************************************/
public int getValueIndex()
{
return (this.valueIndex);
}
/*******************************************************************************
** Setter for valueIndex
*******************************************************************************/
public void setValueIndex(int valueIndex)
{
this.valueIndex = valueIndex;
}
/*******************************************************************************
** Fluent setter for valueIndex
*******************************************************************************/
public FilterVariableExpression withValueIndex(int valueIndex)
{
this.valueIndex = valueIndex;
return (this);
}
/*******************************************************************************
** Getter for fieldName
*******************************************************************************/
public String getFieldName()
{
return (this.fieldName);
}
/*******************************************************************************
** Setter for fieldName
*******************************************************************************/
public void setFieldName(String fieldName)
{
this.fieldName = fieldName;
}
/*******************************************************************************
** Fluent setter for fieldName
*******************************************************************************/
public FilterVariableExpression withFieldName(String fieldName)
{
this.fieldName = fieldName;
return (this);
}
/*******************************************************************************
** Getter for variableName
*******************************************************************************/
public String getVariableName()
{
return (this.variableName);
}
/*******************************************************************************
** Setter for variableName
*******************************************************************************/
public void setVariableName(String variableName)
{
this.variableName = variableName;
}
/*******************************************************************************
** Fluent setter for variableName
*******************************************************************************/
public FilterVariableExpression withVariableName(String variableName)
{
this.variableName = variableName;
return (this);
}
/*******************************************************************************
** Getter for operator
*******************************************************************************/
public String getOperator()
{
return (this.operator);
}
/*******************************************************************************
** Setter for operator
*******************************************************************************/
public void setOperator(String operator)
{
this.operator = operator;
}
/*******************************************************************************
** Fluent setter for operator
*******************************************************************************/
public FilterVariableExpression withOperator(String operator)
{
this.operator = operator;
return (this);
}
}

View File

@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions;
import java.time.Instant; import java.time.Instant;
import com.kingsrook.qqq.backend.core.exceptions.QException;
/******************************************************************************* /*******************************************************************************
@ -35,7 +36,7 @@ public class Now extends AbstractFilterExpression<Instant>
** **
*******************************************************************************/ *******************************************************************************/
@Override @Override
public Instant evaluate() public Instant evaluate() throws QException
{ {
return (Instant.now()); return (Instant.now());
} }

View File

@ -28,6 +28,7 @@ import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.kingsrook.qqq.backend.core.exceptions.QException;
/******************************************************************************* /*******************************************************************************
@ -119,7 +120,7 @@ public class NowWithOffset extends AbstractFilterExpression<Instant>
** **
*******************************************************************************/ *******************************************************************************/
@Override @Override
public Instant evaluate() public Instant evaluate() throws QException
{ {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Instant doesn't let us plus/minus WEEK, MONTH, or YEAR... // // Instant doesn't let us plus/minus WEEK, MONTH, or YEAR... //

View File

@ -28,6 +28,7 @@ import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.temporal.ChronoField; import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException; import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException;
import com.kingsrook.qqq.backend.core.utils.ValueUtils; import com.kingsrook.qqq.backend.core.utils.ValueUtils;
@ -95,7 +96,7 @@ public class ThisOrLastPeriod extends AbstractFilterExpression<Instant>
** **
*******************************************************************************/ *******************************************************************************/
@Override @Override
public Instant evaluate() public Instant evaluate() throws QException
{ {
ZoneId zoneId = ValueUtils.getSessionOrInstanceZoneId(); ZoneId zoneId = ValueUtils.getSessionOrInstanceZoneId();

View File

@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTa
import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableGroupBy; import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableGroupBy;
import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableValue; import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableValue;
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.query.QQueryFilter;
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.data.QRecord; 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.metadata.tables.QTableMetaData;
@ -110,10 +111,12 @@ public class SavedReportTableCustomizer implements TableCustomizerInterface
{ {
try try
{ {
//////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// nothing to validate on filter, other than, we can parse it // // validate that we can parse the filter, then prep it for the backend //
//////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
SavedReportToReportMetaDataAdapter.getQQueryFilter(queryFilterJson); QQueryFilter filter = SavedReportToReportMetaDataAdapter.getQQueryFilter(queryFilterJson);
filter.prepForBackend();
record.setValue("queryFilterJson", filter);
} }
catch(IOException e) catch(IOException e)
{ {

View File

@ -32,6 +32,8 @@ import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
@ -50,6 +52,9 @@ import org.apache.commons.lang.NotImplementedException;
*******************************************************************************/ *******************************************************************************/
public class BackendQueryFilterUtils public class BackendQueryFilterUtils
{ {
private static final QLogger LOG = QLogger.getLogger(BackendQueryFilterUtils.class);
/******************************************************************************* /*******************************************************************************
** Test if record matches filter. ** Test if record matches filter.
@ -138,7 +143,14 @@ public class BackendQueryFilterUtils
Serializable criteriaValue = valueListIterator.next(); Serializable criteriaValue = valueListIterator.next();
if(criteriaValue instanceof AbstractFilterExpression<?> expression) if(criteriaValue instanceof AbstractFilterExpression<?> expression)
{ {
valueListIterator.set(expression.evaluate()); try
{
valueListIterator.set(expression.evaluate());
}
catch(QException qe)
{
LOG.warn("Unexpected exception caught evaluating expression", qe);
}
} }
} }

View File

@ -0,0 +1,100 @@
/*
* 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.tables;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.kingsrook.qqq.backend.core.BaseTest;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.AbstractFilterExpression;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.FilterVariableExpression;
import org.junit.jupiter.api.Test;
import static com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator.BETWEEN;
import static com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator.EQUALS;
import static com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator.IS_BLANK;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
** Unit test for QQueryFilter
**
*******************************************************************************/
class QQueryFilterTest extends BaseTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
public void testInterpretValues() throws QException
{
Map<String, Serializable> inputValues = new HashMap<>();
inputValues.put("clientIdEquals1", "value");
AbstractFilterExpression<Serializable> expression = new FilterVariableExpression()
.withVariableName("clientIdEquals1");
QQueryFilter qQueryFilter = new QQueryFilter(new QFilterCriteria("id", EQUALS, expression));
qQueryFilter.interpretValues(inputValues);
assertEquals("value", qQueryFilter.getCriteria().get(0).getValues().get(0));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
public void testPrepForBackend() throws QException
{
FilterVariableExpression fve0 = new FilterVariableExpression();
FilterVariableExpression fve1 = new FilterVariableExpression();
FilterVariableExpression fve2 = new FilterVariableExpression();
FilterVariableExpression fve3 = new FilterVariableExpression();
FilterVariableExpression fve4 = new FilterVariableExpression();
FilterVariableExpression fve5 = new FilterVariableExpression();
FilterVariableExpression fve6 = new FilterVariableExpression();
QQueryFilter qQueryFilter = new QQueryFilter(
new QFilterCriteria("id", EQUALS, fve0),
new QFilterCriteria("value", IS_BLANK, fve1),
new QFilterCriteria("id", EQUALS, fve2),
new QFilterCriteria("id", BETWEEN, fve3, fve4),
new QFilterCriteria("id", BETWEEN, fve5, fve6)
);
qQueryFilter.prepForBackend();
assertEquals("idEquals", fve0.getVariableName());
assertEquals("valueIsBlank", fve1.getVariableName());
assertEquals("idEquals2", fve2.getVariableName());
assertEquals("idBetweenFrom", fve3.getVariableName());
assertEquals("idBetweenTo", fve4.getVariableName());
assertEquals("idBetweenFrom2", fve5.getVariableName());
assertEquals("idBetweenTo2", fve6.getVariableName());
}
}

View File

@ -42,7 +42,7 @@ class NowWithOffsetTest extends BaseTest
** **
*******************************************************************************/ *******************************************************************************/
@Test @Test
void test() void test() throws Exception
{ {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();

View File

@ -37,7 +37,9 @@ import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTa
import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableValue; import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableValue;
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;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
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.tables.query.expressions.FilterVariableExpression;
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;
@ -45,6 +47,7 @@ import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.TestUtils; import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator.EQUALS;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -98,6 +101,31 @@ class SavedReportTableCustomizerTest extends BaseTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testPrepareFilterVariable()
{
QQueryFilter qQueryFilter = new QQueryFilter(new QFilterCriteria("id", EQUALS, new FilterVariableExpression()));
QRecord record = new SavedReport()
.withTableName(TestUtils.TABLE_NAME_PERSON_MEMORY)
.withQueryFilterJson(JsonUtils.toJson(qQueryFilter))
.withColumnsJson(JsonUtils.toJson(new ReportColumns()
.withColumn("id")
.withColumn("firstName")
.withColumn("lastName")
.withColumn("birthDate")))
.toQRecord();
new SavedReportTableCustomizer().preValidateRecord(record);
assertThat(record.getValueString("queryFilterJson").contains("idEquals"));
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -224,5 +252,4 @@ class SavedReportTableCustomizerTest extends BaseTest
List.of("Missing function for at least one pivot table value")); List.of("Missing function for at least one pivot table value"));
} }
} }

View File

@ -189,7 +189,7 @@ public class AbstractMongoDBAction
Map<String, Serializable> values = record.getValues(); Map<String, Serializable> values = record.getValues();
for(QFieldMetaData field : table.getFields().values()) for(QFieldMetaData field : table.getFields().values())
{ {
String fieldName = field.getName(); String fieldName = field.getName();
String fieldBackendName = getFieldBackendName(field); String fieldBackendName = getFieldBackendName(field);
if(fieldBackendName.contains(".")) if(fieldBackendName.contains("."))
@ -554,7 +554,14 @@ public class AbstractMongoDBAction
Serializable value = valueListIterator.next(); Serializable value = valueListIterator.next();
if(value instanceof AbstractFilterExpression<?> expression) if(value instanceof AbstractFilterExpression<?> expression)
{ {
valueListIterator.set(expression.evaluate()); try
{
valueListIterator.set(expression.evaluate());
}
catch(QException qe)
{
LOG.warn("Unexpected exception caught evaluating expression", qe);
}
} }
/* /*
todo - is this needed?? todo - is this needed??

View File

@ -43,6 +43,7 @@ import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QValueException; import com.kingsrook.qqq.backend.core.exceptions.QValueException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
@ -617,7 +618,14 @@ public abstract class AbstractRDBMSAction
Serializable value = valueListIterator.next(); Serializable value = valueListIterator.next();
if(value instanceof AbstractFilterExpression<?> expression) if(value instanceof AbstractFilterExpression<?> expression)
{ {
valueListIterator.set(expression.evaluate()); try
{
valueListIterator.set(expression.evaluate());
}
catch(QException qe)
{
LOG.warn("Unexpected exception caught evaluating expression", qe);
}
} }
else else
{ {

View File

@ -32,6 +32,7 @@ import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -1244,7 +1245,9 @@ public class QJavalinImplementation
} }
if(filter != null) if(filter != null)
{ {
queryInput.setFilter(JsonUtils.toObject(filter, QQueryFilter.class)); QQueryFilter qQueryFilter = JsonUtils.toObject(filter, QQueryFilter.class);
queryInput.setFilter(qQueryFilter);
qQueryFilter.interpretValues(Collections.emptyMap());
} }
Integer skip = QJavalinUtils.integerQueryParam(context, "skip"); Integer skip = QJavalinUtils.integerQueryParam(context, "skip");
@ -1962,6 +1965,7 @@ public class QJavalinImplementation
} }
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/