mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Updating to support possible value searching
This commit is contained in:
@ -111,7 +111,35 @@ public class QPossibleValueTranslator
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
** Translate a list of ids to a list of possible values (e.g., w/ rendered values)
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QPossibleValue<?>> buildTranslatedPossibleValueList(QPossibleValueSource possibleValueSource, List<Serializable> ids)
|
||||||
|
{
|
||||||
|
if(ids == null)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ids.isEmpty())
|
||||||
|
{
|
||||||
|
return (new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<QPossibleValue<?>> rs = new ArrayList<>();
|
||||||
|
primePvsCache(possibleValueSource.getTableName(), List.of(possibleValueSource), ids);
|
||||||
|
for(Serializable id : ids)
|
||||||
|
{
|
||||||
|
String translated = translatePossibleValue(possibleValueSource, id);
|
||||||
|
rs.add(new QPossibleValue<>(id, translated));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** For a given field and (raw/id) value, get the translated (string) value.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
String translatePossibleValue(QFieldMetaData field, Serializable value)
|
String translatePossibleValue(QFieldMetaData field, Serializable value)
|
||||||
{
|
{
|
||||||
@ -122,6 +150,16 @@ public class QPossibleValueTranslator
|
|||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return translatePossibleValue(possibleValueSource, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** For a given PossibleValueSource and (raw/id) value, get the translated (string) value.
|
||||||
|
*******************************************************************************/
|
||||||
|
String translatePossibleValue(QPossibleValueSource possibleValueSource, Serializable value)
|
||||||
|
{
|
||||||
String resultValue = null;
|
String resultValue = null;
|
||||||
if(possibleValueSource.getType().equals(QPossibleValueSourceType.ENUM))
|
if(possibleValueSource.getType().equals(QPossibleValueSourceType.ENUM))
|
||||||
{
|
{
|
||||||
@ -129,15 +167,15 @@ public class QPossibleValueTranslator
|
|||||||
}
|
}
|
||||||
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.TABLE))
|
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.TABLE))
|
||||||
{
|
{
|
||||||
resultValue = translatePossibleValueTable(field, value, possibleValueSource);
|
resultValue = translatePossibleValueTable(value, possibleValueSource);
|
||||||
}
|
}
|
||||||
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.CUSTOM))
|
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.CUSTOM))
|
||||||
{
|
{
|
||||||
resultValue = translatePossibleValueCustom(field, value, possibleValueSource);
|
resultValue = translatePossibleValueCustom(value, possibleValueSource);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG.error("Unrecognized possibleValueSourceType [" + possibleValueSource.getType() + "] in PVS named [" + possibleValueSource.getName() + "] on field [" + field.getName() + "]");
|
LOG.error("Unrecognized possibleValueSourceType [" + possibleValueSource.getType() + "] in PVS named [" + possibleValueSource.getName() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(resultValue == null)
|
if(resultValue == null)
|
||||||
@ -151,7 +189,7 @@ public class QPossibleValueTranslator
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
** do translation for an enum-type PVS
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private String translatePossibleValueEnum(Serializable value, QPossibleValueSource possibleValueSource)
|
private String translatePossibleValueEnum(Serializable value, QPossibleValueSource possibleValueSource)
|
||||||
{
|
{
|
||||||
@ -169,9 +207,9 @@ public class QPossibleValueTranslator
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
** do translation for a table-type PVS
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private String translatePossibleValueTable(QFieldMetaData field, Serializable value, QPossibleValueSource possibleValueSource)
|
String translatePossibleValueTable(Serializable value, QPossibleValueSource possibleValueSource)
|
||||||
{
|
{
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
// null input gets null output //
|
// null input gets null output //
|
||||||
@ -197,9 +235,9 @@ public class QPossibleValueTranslator
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
** do translation for a custom-type PVS
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private String translatePossibleValueCustom(QFieldMetaData field, Serializable value, QPossibleValueSource possibleValueSource)
|
private String translatePossibleValueCustom(Serializable value, QPossibleValueSource possibleValueSource)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -208,7 +246,7 @@ public class QPossibleValueTranslator
|
|||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn("Error sending [" + value + "] for field [" + field + "] through custom code for PVS [" + field.getPossibleValueSourceName() + "]", e);
|
LOG.warn("Error sending [" + value + "] for through custom code for PVS [" + possibleValueSource.getName() + "]", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (null);
|
return (null);
|
||||||
|
@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
|
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.QueryInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceOutput;
|
||||||
|
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.possiblevalues.QPossibleValue;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
import org.apache.commons.lang.NotImplementedException;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Class responsible for looking up possible-values for fields/records and
|
||||||
|
** make them into display values.
|
||||||
|
*******************************************************************************/
|
||||||
|
public class SearchPossibleValueSourceAction
|
||||||
|
{
|
||||||
|
private static final Logger LOG = LogManager.getLogger(SearchPossibleValueSourceAction.class);
|
||||||
|
|
||||||
|
private QPossibleValueTranslator possibleValueTranslator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceOutput execute(SearchPossibleValueSourceInput input) throws QException
|
||||||
|
{
|
||||||
|
QInstance qInstance = input.getInstance();
|
||||||
|
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(input.getPossibleValueSourceName());
|
||||||
|
if(possibleValueSource == null)
|
||||||
|
{
|
||||||
|
throw new QException("Missing possible value source named [" + input.getPossibleValueSourceName() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
possibleValueTranslator = new QPossibleValueTranslator(input.getInstance(), input.getSession());
|
||||||
|
SearchPossibleValueSourceOutput output = null;
|
||||||
|
if(possibleValueSource.getType().equals(QPossibleValueSourceType.ENUM))
|
||||||
|
{
|
||||||
|
output = searchPossibleValueEnum(input, possibleValueSource);
|
||||||
|
}
|
||||||
|
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.TABLE))
|
||||||
|
{
|
||||||
|
output = searchPossibleValueTable(input, possibleValueSource);
|
||||||
|
}
|
||||||
|
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.CUSTOM))
|
||||||
|
{
|
||||||
|
output = searchPossibleValueCustom(input, possibleValueSource);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG.error("Unrecognized possibleValueSourceType [" + possibleValueSource.getType() + "] in PVS named [" + possibleValueSource.getName() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private SearchPossibleValueSourceOutput searchPossibleValueEnum(SearchPossibleValueSourceInput input, QPossibleValueSource possibleValueSource)
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceOutput();
|
||||||
|
List<Serializable> matchingIds = new ArrayList<>();
|
||||||
|
|
||||||
|
for(QPossibleValue<?> possibleValue : possibleValueSource.getEnumValues())
|
||||||
|
{
|
||||||
|
boolean match = false;
|
||||||
|
|
||||||
|
if(input.getIdList() != null)
|
||||||
|
{
|
||||||
|
if(input.getIdList().contains(possibleValue.getId()))
|
||||||
|
{
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(StringUtils.hasContent(input.getSearchTerm()))
|
||||||
|
{
|
||||||
|
match = (Objects.equals(ValueUtils.getValueAsString(possibleValue.getId()).toLowerCase(), input.getSearchTerm().toLowerCase())
|
||||||
|
|| possibleValue.getLabel().toLowerCase().startsWith(input.getSearchTerm().toLowerCase()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(match)
|
||||||
|
{
|
||||||
|
matchingIds.add((Serializable) possibleValue.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo - skip & limit?
|
||||||
|
// todo - default filter
|
||||||
|
}
|
||||||
|
|
||||||
|
List<QPossibleValue<?>> qPossibleValues = possibleValueTranslator.buildTranslatedPossibleValueList(possibleValueSource, matchingIds);
|
||||||
|
output.setResults(qPossibleValues);
|
||||||
|
|
||||||
|
return (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private SearchPossibleValueSourceOutput searchPossibleValueTable(SearchPossibleValueSourceInput input, QPossibleValueSource possibleValueSource) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceOutput();
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(input.getInstance());
|
||||||
|
queryInput.setSession(input.getSession());
|
||||||
|
queryInput.setTableName(possibleValueSource.getTableName());
|
||||||
|
|
||||||
|
QTableMetaData table = input.getInstance().getTable(possibleValueSource.getTableName());
|
||||||
|
|
||||||
|
QQueryFilter queryFilter = new QQueryFilter();
|
||||||
|
queryFilter.setBooleanOperator(QQueryFilter.BooleanOperator.OR);
|
||||||
|
queryInput.setFilter(queryFilter);
|
||||||
|
|
||||||
|
if(input.getIdList() != null)
|
||||||
|
{
|
||||||
|
queryFilter.addCriteria(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, input.getIdList()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(StringUtils.hasContent(input.getSearchTerm()))
|
||||||
|
{
|
||||||
|
for(String valueField : possibleValueSource.getSearchFields())
|
||||||
|
{
|
||||||
|
QFieldMetaData field = table.getField(valueField);
|
||||||
|
if(field.getType().equals(QFieldType.STRING))
|
||||||
|
{
|
||||||
|
queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.STARTS_WITH, List.of(input.getSearchTerm())));
|
||||||
|
}
|
||||||
|
else if(field.getType().equals(QFieldType.DATE) || field.getType().equals(QFieldType.DATE_TIME))
|
||||||
|
{
|
||||||
|
LOG.debug("Not querying PVS [" + possibleValueSource.getName() + "] on date field [" + field.getName() + "]");
|
||||||
|
// todo - what? queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.STARTS_WITH, List.of(input.getSearchTerm())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Integer valueAsInteger = ValueUtils.getValueAsInteger(input.getSearchTerm());
|
||||||
|
if(valueAsInteger != null)
|
||||||
|
{
|
||||||
|
queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.EQUALS, List.of(valueAsInteger)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
// write a FALSE criteria if the value isn't a number //
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.IN, List.of()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queryFilter.setOrderBys(possibleValueSource.getOrderByFields());
|
||||||
|
|
||||||
|
// todo - default filter
|
||||||
|
|
||||||
|
// todo - skip & limit as params
|
||||||
|
queryInput.setLimit(250);
|
||||||
|
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
List<Serializable> ids = queryOutput.getRecords().stream().map(r -> r.getValue(table.getPrimaryKeyField())).toList();
|
||||||
|
List<QPossibleValue<?>> qPossibleValues = possibleValueTranslator.buildTranslatedPossibleValueList(possibleValueSource, ids);
|
||||||
|
output.setResults(qPossibleValues);
|
||||||
|
|
||||||
|
return (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private SearchPossibleValueSourceOutput searchPossibleValueCustom(SearchPossibleValueSourceInput input, QPossibleValueSource possibleValueSource)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// QCustomPossibleValueProvider customPossibleValueProvider = QCodeLoader.getCustomPossibleValueProvider(possibleValueSource);
|
||||||
|
// return (formatPossibleValue(possibleValueSource, customPossibleValueProvider.getPossibleValue(value)));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
// LOG.warn("Error sending [" + value + "] for field [" + field + "] through custom code for PVS [" + field.getPossibleValueSourceName() + "]", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException("Not impleemnted");
|
||||||
|
// return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -121,6 +121,11 @@ public class QInstanceEnricher
|
|||||||
{
|
{
|
||||||
qInstance.getReports().values().forEach(this::enrichReport);
|
qInstance.getReports().values().forEach(this::enrichReport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(qInstance.getPossibleValueSources() != null)
|
||||||
|
{
|
||||||
|
qInstance.getPossibleValueSources().values().forEach(this::enrichPossibleValueSource);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -748,4 +753,50 @@ public class QInstanceEnricher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void enrichPossibleValueSource(QPossibleValueSource possibleValueSource)
|
||||||
|
{
|
||||||
|
if(QPossibleValueSourceType.TABLE.equals(possibleValueSource.getType()))
|
||||||
|
{
|
||||||
|
if(CollectionUtils.nullSafeIsEmpty(possibleValueSource.getSearchFields()))
|
||||||
|
{
|
||||||
|
QTableMetaData table = qInstance.getTable(possibleValueSource.getTableName());
|
||||||
|
if(table != null)
|
||||||
|
{
|
||||||
|
if(table.getPrimaryKeyField() != null)
|
||||||
|
{
|
||||||
|
possibleValueSource.withSearchField(table.getPrimaryKeyField());
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String recordLabelField : CollectionUtils.nonNullList(table.getRecordLabelFields()))
|
||||||
|
{
|
||||||
|
possibleValueSource.withSearchField(recordLabelField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeIsEmpty(possibleValueSource.getOrderByFields()))
|
||||||
|
{
|
||||||
|
QTableMetaData table = qInstance.getTable(possibleValueSource.getTableName());
|
||||||
|
if(table != null)
|
||||||
|
{
|
||||||
|
for(String recordLabelField : CollectionUtils.nonNullList(table.getRecordLabelFields()))
|
||||||
|
{
|
||||||
|
possibleValueSource.withOrderByField(recordLabelField);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(table.getPrimaryKeyField() != null)
|
||||||
|
{
|
||||||
|
possibleValueSource.withOrderByField(table.getPrimaryKeyField());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||||
import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider;
|
import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||||
@ -715,6 +716,8 @@ public class QInstanceValidator
|
|||||||
case ENUM ->
|
case ENUM ->
|
||||||
{
|
{
|
||||||
assertCondition(!StringUtils.hasContent(possibleValueSource.getTableName()), "enum-type possibleValueSource " + pvsName + " should not have a tableName.");
|
assertCondition(!StringUtils.hasContent(possibleValueSource.getTableName()), "enum-type possibleValueSource " + pvsName + " should not have a tableName.");
|
||||||
|
assertCondition(!CollectionUtils.nullSafeHasContents(possibleValueSource.getSearchFields()), "enum-type possibleValueSource " + pvsName + " should not have searchFields.");
|
||||||
|
assertCondition(!CollectionUtils.nullSafeHasContents(possibleValueSource.getOrderByFields()), "enum-type possibleValueSource " + pvsName + " should not have orderByFields.");
|
||||||
assertCondition(possibleValueSource.getCustomCodeReference() == null, "enum-type possibleValueSource " + pvsName + " should not have a customCodeReference.");
|
assertCondition(possibleValueSource.getCustomCodeReference() == null, "enum-type possibleValueSource " + pvsName + " should not have a customCodeReference.");
|
||||||
|
|
||||||
assertCondition(CollectionUtils.nullSafeHasContents(possibleValueSource.getEnumValues()), "enum-type possibleValueSource " + pvsName + " is missing enum values");
|
assertCondition(CollectionUtils.nullSafeHasContents(possibleValueSource.getEnumValues()), "enum-type possibleValueSource " + pvsName + " is missing enum values");
|
||||||
@ -724,15 +727,44 @@ public class QInstanceValidator
|
|||||||
assertCondition(CollectionUtils.nullSafeIsEmpty(possibleValueSource.getEnumValues()), "table-type possibleValueSource " + pvsName + " should not have enum values.");
|
assertCondition(CollectionUtils.nullSafeIsEmpty(possibleValueSource.getEnumValues()), "table-type possibleValueSource " + pvsName + " should not have enum values.");
|
||||||
assertCondition(possibleValueSource.getCustomCodeReference() == null, "table-type possibleValueSource " + pvsName + " should not have a customCodeReference.");
|
assertCondition(possibleValueSource.getCustomCodeReference() == null, "table-type possibleValueSource " + pvsName + " should not have a customCodeReference.");
|
||||||
|
|
||||||
|
QTableMetaData tableMetaData = null;
|
||||||
if(assertCondition(StringUtils.hasContent(possibleValueSource.getTableName()), "table-type possibleValueSource " + pvsName + " is missing a tableName."))
|
if(assertCondition(StringUtils.hasContent(possibleValueSource.getTableName()), "table-type possibleValueSource " + pvsName + " is missing a tableName."))
|
||||||
{
|
{
|
||||||
assertCondition(qInstance.getTable(possibleValueSource.getTableName()) != null, "Unrecognized table " + possibleValueSource.getTableName() + " for possibleValueSource " + pvsName + ".");
|
tableMetaData = qInstance.getTable(possibleValueSource.getTableName());
|
||||||
|
assertCondition(tableMetaData != null, "Unrecognized table " + possibleValueSource.getTableName() + " for possibleValueSource " + pvsName + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(assertCondition(CollectionUtils.nullSafeHasContents(possibleValueSource.getSearchFields()), "table-type possibleValueSource " + pvsName + " is missing searchFields."))
|
||||||
|
{
|
||||||
|
if(tableMetaData != null)
|
||||||
|
{
|
||||||
|
QTableMetaData finalTableMetaData = tableMetaData;
|
||||||
|
for(String searchField : possibleValueSource.getSearchFields())
|
||||||
|
{
|
||||||
|
assertNoException(() -> finalTableMetaData.getField(searchField), "possibleValueSource " + pvsName + " has an unrecognized searchField: " + searchField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(assertCondition(CollectionUtils.nullSafeHasContents(possibleValueSource.getOrderByFields()), "table-type possibleValueSource " + pvsName + " is missing orderByFields."))
|
||||||
|
{
|
||||||
|
if(tableMetaData != null)
|
||||||
|
{
|
||||||
|
QTableMetaData finalTableMetaData = tableMetaData;
|
||||||
|
|
||||||
|
for(QFilterOrderBy orderByField : possibleValueSource.getOrderByFields())
|
||||||
|
{
|
||||||
|
assertNoException(() -> finalTableMetaData.getField(orderByField.getFieldName()), "possibleValueSource " + pvsName + " has an unrecognized orderByField: " + orderByField.getFieldName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case CUSTOM ->
|
case CUSTOM ->
|
||||||
{
|
{
|
||||||
assertCondition(CollectionUtils.nullSafeIsEmpty(possibleValueSource.getEnumValues()), "custom-type possibleValueSource " + pvsName + " should not have enum values.");
|
assertCondition(CollectionUtils.nullSafeIsEmpty(possibleValueSource.getEnumValues()), "custom-type possibleValueSource " + pvsName + " should not have enum values.");
|
||||||
assertCondition(!StringUtils.hasContent(possibleValueSource.getTableName()), "custom-type possibleValueSource " + pvsName + " should not have a tableName.");
|
assertCondition(!StringUtils.hasContent(possibleValueSource.getTableName()), "custom-type possibleValueSource " + pvsName + " should not have a tableName.");
|
||||||
|
assertCondition(!CollectionUtils.nullSafeHasContents(possibleValueSource.getSearchFields()), "custom-type possibleValueSource " + pvsName + " should not have searchFields.");
|
||||||
|
assertCondition(!CollectionUtils.nullSafeHasContents(possibleValueSource.getOrderByFields()), "custom-type possibleValueSource " + pvsName + " should not have orderByFields.");
|
||||||
|
|
||||||
if(assertCondition(possibleValueSource.getCustomCodeReference() != null, "custom-type possibleValueSource " + pvsName + " is missing a customCodeReference."))
|
if(assertCondition(possibleValueSource.getCustomCodeReference() != null, "custom-type possibleValueSource " + pvsName + " is missing a customCodeReference."))
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* 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.actions.values;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
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.metadata.QInstance;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Input for the Search possible value source action
|
||||||
|
*******************************************************************************/
|
||||||
|
public class SearchPossibleValueSourceInput extends AbstractActionInput
|
||||||
|
{
|
||||||
|
private String possibleValueSourceName;
|
||||||
|
private QQueryFilter defaultQueryFilter;
|
||||||
|
private String searchTerm;
|
||||||
|
private List<Serializable> idList;
|
||||||
|
|
||||||
|
private Integer skip = 0;
|
||||||
|
private Integer limit = 100;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput(QInstance instance)
|
||||||
|
{
|
||||||
|
super(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for possibleValueSourceName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getPossibleValueSourceName()
|
||||||
|
{
|
||||||
|
return possibleValueSourceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for possibleValueSourceName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setPossibleValueSourceName(String possibleValueSourceName)
|
||||||
|
{
|
||||||
|
this.possibleValueSourceName = possibleValueSourceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for possibleValueSourceName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput withPossibleValueSourceName(String possibleValueSourceName)
|
||||||
|
{
|
||||||
|
this.possibleValueSourceName = possibleValueSourceName;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for defaultQueryFilter
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QQueryFilter getDefaultQueryFilter()
|
||||||
|
{
|
||||||
|
return defaultQueryFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for defaultQueryFilter
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setDefaultQueryFilter(QQueryFilter defaultQueryFilter)
|
||||||
|
{
|
||||||
|
this.defaultQueryFilter = defaultQueryFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for defaultQueryFilter
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput withDefaultQueryFilter(QQueryFilter defaultQueryFilter)
|
||||||
|
{
|
||||||
|
this.defaultQueryFilter = defaultQueryFilter;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for searchTerm
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getSearchTerm()
|
||||||
|
{
|
||||||
|
return searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for searchTerm
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setSearchTerm(String searchTerm)
|
||||||
|
{
|
||||||
|
this.searchTerm = searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for searchTerm
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput withSearchTerm(String searchTerm)
|
||||||
|
{
|
||||||
|
this.searchTerm = searchTerm;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for idList
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<Serializable> getIdList()
|
||||||
|
{
|
||||||
|
return idList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for idList
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIdList(List<Serializable> idList)
|
||||||
|
{
|
||||||
|
this.idList = idList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for idList
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput withIdList(List<Serializable> idList)
|
||||||
|
{
|
||||||
|
this.idList = idList;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for skip
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getSkip()
|
||||||
|
{
|
||||||
|
return skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for skip
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setSkip(Integer skip)
|
||||||
|
{
|
||||||
|
this.skip = skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for skip
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput withSkip(Integer skip)
|
||||||
|
{
|
||||||
|
this.skip = skip;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for limit
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Integer getLimit()
|
||||||
|
{
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for limit
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setLimit(Integer limit)
|
||||||
|
{
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for limit
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput withLimit(Integer limit)
|
||||||
|
{
|
||||||
|
this.limit = limit;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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.actions.values;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Output for the Search possible value source action
|
||||||
|
*******************************************************************************/
|
||||||
|
public class SearchPossibleValueSourceOutput extends AbstractActionOutput
|
||||||
|
{
|
||||||
|
private List<QPossibleValue<?>> results = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceOutput()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void addResult(QPossibleValue<?> possibleValue)
|
||||||
|
{
|
||||||
|
results.add(possibleValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for results
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QPossibleValue<?>> getResults()
|
||||||
|
{
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for results
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setResults(List<QPossibleValue<?>> results)
|
||||||
|
{
|
||||||
|
this.results = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for results
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceOutput withResults(List<QPossibleValue<?>> results)
|
||||||
|
{
|
||||||
|
this.results = results;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.possiblevalues;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +50,8 @@ public class QPossibleValueSource
|
|||||||
// for type = TABLE //
|
// for type = TABLE //
|
||||||
//////////////////////
|
//////////////////////
|
||||||
private String tableName;
|
private String tableName;
|
||||||
// todo - override labelFormat & labelFields?
|
private List<String> searchFields;
|
||||||
|
private List<QFilterOrderBy> orderByFields;
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// for type = ENUM //
|
// for type = ENUM //
|
||||||
@ -304,6 +306,128 @@ public class QPossibleValueSource
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for searchFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<String> getSearchFields()
|
||||||
|
{
|
||||||
|
return searchFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for searchFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setSearchFields(List<String> searchFields)
|
||||||
|
{
|
||||||
|
this.searchFields = searchFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for searchFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QPossibleValueSource withSearchFields(List<String> searchFields)
|
||||||
|
{
|
||||||
|
this.searchFields = searchFields;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for searchFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QPossibleValueSource withSearchField(String searchField)
|
||||||
|
{
|
||||||
|
if(this.searchFields == null)
|
||||||
|
{
|
||||||
|
this.searchFields = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.searchFields.add(searchField);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for orderByFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QFilterOrderBy> getOrderByFields()
|
||||||
|
{
|
||||||
|
return orderByFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for orderByFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setOrderByFields(List<QFilterOrderBy> orderByFields)
|
||||||
|
{
|
||||||
|
this.orderByFields = orderByFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for orderByFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QPossibleValueSource withOrderByFields(List<QFilterOrderBy> orderByFields)
|
||||||
|
{
|
||||||
|
this.orderByFields = orderByFields;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for orderByFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QPossibleValueSource withOrderByField(QFilterOrderBy orderByField)
|
||||||
|
{
|
||||||
|
if(this.orderByFields == null)
|
||||||
|
{
|
||||||
|
this.orderByFields = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.orderByFields.add(orderByField);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for orderByFields - default to ASCENDING
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QPossibleValueSource withOrderByField(String fieldName)
|
||||||
|
{
|
||||||
|
return (withOrderByField(new QFilterOrderBy(fieldName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for orderByFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QPossibleValueSource withOrderByField(String fieldName, boolean isAscending)
|
||||||
|
{
|
||||||
|
return (withOrderByField(new QFilterOrderBy(fieldName, isAscending)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for enumValues
|
** Getter for enumValues
|
||||||
**
|
**
|
||||||
|
@ -364,7 +364,17 @@ public class MemoryRecordStore
|
|||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!value.equals(criterion.getValues().get(0)))
|
Serializable criteriaValue = criterion.getValues().get(0);
|
||||||
|
if(value instanceof String && criteriaValue instanceof Number)
|
||||||
|
{
|
||||||
|
criteriaValue = String.valueOf(criteriaValue);
|
||||||
|
}
|
||||||
|
else if(criteriaValue instanceof String && value instanceof Number)
|
||||||
|
{
|
||||||
|
value = String.valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!value.equals(criteriaValue))
|
||||||
{
|
{
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
@ -454,8 +454,15 @@ public class ValueUtils
|
|||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
return Instant.parse(s);
|
return Instant.parse(s);
|
||||||
}
|
}
|
||||||
|
catch(DateTimeParseException e)
|
||||||
|
{
|
||||||
|
return tryAlternativeInstantParsing(s, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw (new QValueException("Unsupported class " + value.getClass().getName() + " for converting to Instant."));
|
throw (new QValueException("Unsupported class " + value.getClass().getName() + " for converting to Instant."));
|
||||||
@ -473,6 +480,26 @@ public class ValueUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static Instant tryAlternativeInstantParsing(String s, DateTimeParseException e)
|
||||||
|
{
|
||||||
|
if(s.matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$"))
|
||||||
|
{
|
||||||
|
//////////////////////////
|
||||||
|
// todo ... time zone?? //
|
||||||
|
//////////////////////////
|
||||||
|
return Instant.parse(s + ":00Z");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.NullAndEmptySource;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for SearchPossibleValueSourceAction
|
||||||
|
*******************************************************************************/
|
||||||
|
class SearchPossibleValueSourceActionTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@BeforeEach
|
||||||
|
@AfterEach
|
||||||
|
void beforeAndAfterEach() throws QException
|
||||||
|
{
|
||||||
|
MemoryRecordStore.getInstance().reset();
|
||||||
|
TestUtils.insertDefaultShapes(TestUtils.defineInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@ParameterizedTest
|
||||||
|
@NullAndEmptySource
|
||||||
|
@ValueSource(strings = { " " })
|
||||||
|
void testSearchPvsAction_enumNullAndEmptySearchTerms(String searchTerm) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput(searchTerm, TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(2, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1) && pv.getLabel().equals("IL"));
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("MO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = { "I", "IL", "1", "i", "iL", "il" })
|
||||||
|
void testSearchPvsAction_enumMatchesForIL(String searchTerm) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput(searchTerm, TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(1, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1) && pv.getLabel().equals("IL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = { "3", "ILL" })
|
||||||
|
void testSearchPvsAction_enumMatchesNothing(String searchTerm) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput(searchTerm, TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(0, output.getResults().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSearchPvsAction_enumById() throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputById(2, TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(1, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("MO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSearchPvsAction_enumByIdNotFound() throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputById(-1, TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(0, output.getResults().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@ParameterizedTest
|
||||||
|
@NullAndEmptySource
|
||||||
|
@ValueSource(strings = { " " })
|
||||||
|
void testSearchPvsAction_tableNullAndEmptySearchTerms(String searchTerm) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput(searchTerm, TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(3, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1) && pv.getLabel().equals("Triangle"));
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("Square"));
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(3) && pv.getLabel().equals("Circle"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = { "1", "Triangle" })
|
||||||
|
void testSearchPvsAction_tableMatchesOne(String searchTerm) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput(searchTerm, TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(1, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1) && pv.getLabel().equals("Triangle"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSearchPvsAction_tableById() throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputById(2, TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(1, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("Square"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSearchPvsAction_tableByIds() throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByIds(List.of(2, 3), TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(2, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("Square"));
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(3) && pv.getLabel().equals("Circle"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSearchPvsAction_tableByIdNotFound() throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputById(-1, TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(0, output.getResults().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private SearchPossibleValueSourceOutput getSearchPossibleValueSourceOutput(String searchTerm, String possibleValueSourceName) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceInput input = new SearchPossibleValueSourceInput(TestUtils.defineInstance());
|
||||||
|
input.setSession(new QSession());
|
||||||
|
input.setSearchTerm(searchTerm);
|
||||||
|
input.setPossibleValueSourceName(possibleValueSourceName);
|
||||||
|
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(input);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private SearchPossibleValueSourceOutput getSearchPossibleValueSourceOutputById(Serializable id, String possibleValueSourceName) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceInput input = new SearchPossibleValueSourceInput(TestUtils.defineInstance());
|
||||||
|
input.setSession(new QSession());
|
||||||
|
input.setIdList(List.of(id));
|
||||||
|
input.setPossibleValueSourceName(possibleValueSourceName);
|
||||||
|
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(input);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private SearchPossibleValueSourceOutput getSearchPossibleValueSourceOutputByIds(List<Serializable> ids, String possibleValueSourceName) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceInput input = new SearchPossibleValueSourceInput(TestUtils.defineInstance());
|
||||||
|
input.setSession(new QSession());
|
||||||
|
input.setIdList(ids);
|
||||||
|
input.setPossibleValueSourceName(possibleValueSourceName);
|
||||||
|
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(input);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -37,6 +37,7 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInpu
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
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.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
@ -793,10 +794,14 @@ class QInstanceValidatorTest
|
|||||||
assertValidationFailureReasons((qInstance) -> {
|
assertValidationFailureReasons((qInstance) -> {
|
||||||
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
possibleValueSource.setTableName("person");
|
possibleValueSource.setTableName("person");
|
||||||
|
possibleValueSource.setSearchFields(List.of("id"));
|
||||||
|
possibleValueSource.setOrderByFields(List.of(new QFilterOrderBy("id")));
|
||||||
possibleValueSource.setCustomCodeReference(new QCodeReference());
|
possibleValueSource.setCustomCodeReference(new QCodeReference());
|
||||||
possibleValueSource.setEnumValues(null);
|
possibleValueSource.setEnumValues(null);
|
||||||
},
|
},
|
||||||
"should not have a tableName",
|
"should not have a tableName",
|
||||||
|
"should not have searchFields",
|
||||||
|
"should not have orderByFields",
|
||||||
"should not have a customCodeReference",
|
"should not have a customCodeReference",
|
||||||
"is missing enum values");
|
"is missing enum values");
|
||||||
|
|
||||||
@ -815,15 +820,22 @@ class QInstanceValidatorTest
|
|||||||
assertValidationFailureReasons((qInstance) -> {
|
assertValidationFailureReasons((qInstance) -> {
|
||||||
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
possibleValueSource.setTableName(null);
|
possibleValueSource.setTableName(null);
|
||||||
|
possibleValueSource.setSearchFields(null);
|
||||||
|
possibleValueSource.setOrderByFields(new ArrayList<>());
|
||||||
possibleValueSource.setCustomCodeReference(new QCodeReference());
|
possibleValueSource.setCustomCodeReference(new QCodeReference());
|
||||||
possibleValueSource.setEnumValues(List.of(new QPossibleValue<>("test")));
|
possibleValueSource.setEnumValues(List.of(new QPossibleValue<>("test")));
|
||||||
},
|
},
|
||||||
"should not have enum values",
|
"should not have enum values",
|
||||||
"should not have a customCodeReference",
|
"should not have a customCodeReference",
|
||||||
"is missing a tableName");
|
"is missing a tableName",
|
||||||
|
"is missing searchFields",
|
||||||
|
"is missing orderByFields");
|
||||||
|
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE).setTableName("Not a table"),
|
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE).setTableName("Not a table"),
|
||||||
"Unrecognized table");
|
"Unrecognized table");
|
||||||
|
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE).setSearchFields(List.of("id", "notAField", "name")),
|
||||||
|
"unrecognized searchField: notAField");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -837,11 +849,15 @@ class QInstanceValidatorTest
|
|||||||
assertValidationFailureReasons((qInstance) -> {
|
assertValidationFailureReasons((qInstance) -> {
|
||||||
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
|
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
|
||||||
possibleValueSource.setTableName("person");
|
possibleValueSource.setTableName("person");
|
||||||
|
possibleValueSource.setSearchFields(List.of("id"));
|
||||||
|
possibleValueSource.setOrderByFields(List.of(new QFilterOrderBy("id")));
|
||||||
possibleValueSource.setCustomCodeReference(null);
|
possibleValueSource.setCustomCodeReference(null);
|
||||||
possibleValueSource.setEnumValues(List.of(new QPossibleValue<>("test")));
|
possibleValueSource.setEnumValues(List.of(new QPossibleValue<>("test")));
|
||||||
},
|
},
|
||||||
"should not have enum values",
|
"should not have enum values",
|
||||||
"should not have a tableName",
|
"should not have a tableName",
|
||||||
|
"should not have searchFields",
|
||||||
|
"should not have orderByFields",
|
||||||
"is missing a customCodeReference");
|
"is missing a customCodeReference");
|
||||||
|
|
||||||
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM).setCustomCodeReference(new QCodeReference()),
|
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM).setCustomCodeReference(new QCodeReference()),
|
||||||
|
@ -331,7 +331,9 @@ public class TestUtils
|
|||||||
return new QPossibleValueSource()
|
return new QPossibleValueSource()
|
||||||
.withName(POSSIBLE_VALUE_SOURCE_SHAPE)
|
.withName(POSSIBLE_VALUE_SOURCE_SHAPE)
|
||||||
.withType(QPossibleValueSourceType.TABLE)
|
.withType(QPossibleValueSourceType.TABLE)
|
||||||
.withTableName(TABLE_NAME_SHAPE);
|
.withTableName(TABLE_NAME_SHAPE)
|
||||||
|
.withSearchFields(List.of("id", "name"))
|
||||||
|
.withOrderByField("name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import java.io.PipedInputStream;
|
|||||||
import java.io.PipedOutputStream;
|
import java.io.PipedOutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -46,6 +47,7 @@ import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.values.SearchPossibleValueSourceAction;
|
||||||
import com.kingsrook.qqq.backend.core.adapters.QInstanceAdapter;
|
import com.kingsrook.qqq.backend.core.adapters.QInstanceAdapter;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||||
@ -76,10 +78,13 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
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.actions.values.SearchPossibleValueSourceInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceOutput;
|
||||||
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.actions.widgets.RenderWidgetOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
||||||
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.QInstance;
|
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.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule;
|
import com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule;
|
||||||
@ -277,6 +282,7 @@ public class QJavalinImplementation
|
|||||||
get("/count", QJavalinImplementation::dataCount);
|
get("/count", QJavalinImplementation::dataCount);
|
||||||
get("/export", QJavalinImplementation::dataExportWithoutFilename);
|
get("/export", QJavalinImplementation::dataExportWithoutFilename);
|
||||||
get("/export/{filename}", QJavalinImplementation::dataExportWithFilename);
|
get("/export/{filename}", QJavalinImplementation::dataExportWithFilename);
|
||||||
|
get("/possibleValues/{fieldName}", QJavalinImplementation::possibleValues);
|
||||||
|
|
||||||
// todo - add put and/or patch at this level (without a primaryKey) to do a bulk update based on primaryKeys in the records.
|
// todo - add put and/or patch at this level (without a primaryKey) to do a bulk update based on primaryKeys in the records.
|
||||||
path("/{primaryKey}", () ->
|
path("/{primaryKey}", () ->
|
||||||
@ -864,6 +870,64 @@ public class QJavalinImplementation
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static void possibleValues(Context context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String tableName = context.pathParam("table");
|
||||||
|
String fieldName = context.pathParam("fieldName");
|
||||||
|
String searchTerm = context.queryParam("searchTerm");
|
||||||
|
String ids = context.queryParam("ids");
|
||||||
|
|
||||||
|
QTableMetaData table = qInstance.getTable(tableName);
|
||||||
|
if(table == null)
|
||||||
|
{
|
||||||
|
throw (new QNotFoundException("Could not find table named " + tableName + " in this instance."));
|
||||||
|
}
|
||||||
|
|
||||||
|
QFieldMetaData field;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
field = table.getField(fieldName);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
throw (new QNotFoundException("Could not find field named " + fieldName + " in table " + tableName + "."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!StringUtils.hasContent(field.getPossibleValueSourceName()))
|
||||||
|
{
|
||||||
|
throw (new QNotFoundException("Field " + fieldName + " in table " + tableName + " is not associated with a possible value source."));
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPossibleValueSourceInput input = new SearchPossibleValueSourceInput(qInstance);
|
||||||
|
setupSession(context, input);
|
||||||
|
input.setPossibleValueSourceName(field.getPossibleValueSourceName());
|
||||||
|
input.setSearchTerm(searchTerm);
|
||||||
|
|
||||||
|
if(StringUtils.hasContent(ids))
|
||||||
|
{
|
||||||
|
List<Serializable> idList = new ArrayList<>(Arrays.asList(ids.split(",")));
|
||||||
|
input.setIdList(idList);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(input);
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("options", output.getResults());
|
||||||
|
context.result(JsonUtils.toJson(result));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
handleException(context, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -497,4 +497,57 @@ class QJavalinImplementationTest extends QJavalinTestBase
|
|||||||
assertNotNull(jsonObject.getJSONObject("chartData"));
|
assertNotNull(jsonObject.getJSONObject("chartData"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testPossibleValueUnfiltered()
|
||||||
|
{
|
||||||
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/possibleValues/partnerPersonId").asString();
|
||||||
|
assertEquals(200, response.getStatus());
|
||||||
|
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||||
|
assertNotNull(jsonObject);
|
||||||
|
assertNotNull(jsonObject.getJSONArray("options"));
|
||||||
|
assertEquals(5, jsonObject.getJSONArray("options").length());
|
||||||
|
assertEquals(1, jsonObject.getJSONArray("options").getJSONObject(0).getInt("id"));
|
||||||
|
assertEquals("Darin Kelkhoff (1)", jsonObject.getJSONArray("options").getJSONObject(0).getString("label"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testPossibleValueWithSearchTerm()
|
||||||
|
{
|
||||||
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/possibleValues/partnerPersonId?searchTerm=Chamber").asString();
|
||||||
|
assertEquals(200, response.getStatus());
|
||||||
|
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||||
|
assertNotNull(jsonObject);
|
||||||
|
assertNotNull(jsonObject.getJSONArray("options"));
|
||||||
|
assertEquals(1, jsonObject.getJSONArray("options").length());
|
||||||
|
assertEquals("Tim Chamberlain (3)", jsonObject.getJSONArray("options").getJSONObject(0).getString("label"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testPossibleValueWithIds()
|
||||||
|
{
|
||||||
|
HttpResponse<String> response = Unirest.get(BASE_URL + "/data/person/possibleValues/partnerPersonId?ids=4,5").asString();
|
||||||
|
assertEquals(200, response.getStatus());
|
||||||
|
JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody());
|
||||||
|
assertNotNull(jsonObject);
|
||||||
|
assertNotNull(jsonObject.getJSONArray("options"));
|
||||||
|
assertEquals(2, jsonObject.getJSONArray("options").length());
|
||||||
|
assertEquals(4, jsonObject.getJSONArray("options").getJSONObject(0).getInt("id"));
|
||||||
|
assertEquals(5, jsonObject.getJSONArray("options").getJSONObject(1).getInt("id"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,28 +25,31 @@ package com.kingsrook.qqq.backend.javalin;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
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.actions.processes.BackendStep;
|
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
|
||||||
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.processes.RunBackendStepOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||||
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.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
||||||
@ -123,6 +126,7 @@ public class TestUtils
|
|||||||
qInstance.addProcess(defineProcessSimpleSleep());
|
qInstance.addProcess(defineProcessSimpleSleep());
|
||||||
qInstance.addProcess(defineProcessScreenThenSleep());
|
qInstance.addProcess(defineProcessScreenThenSleep());
|
||||||
qInstance.addProcess(defineProcessSimpleThrow());
|
qInstance.addProcess(defineProcessSimpleThrow());
|
||||||
|
qInstance.addPossibleValueSource(definePossibleValueSourcePerson());
|
||||||
defineWidgets(qInstance);
|
defineWidgets(qInstance);
|
||||||
return (qInstance);
|
return (qInstance);
|
||||||
}
|
}
|
||||||
@ -181,6 +185,8 @@ public class TestUtils
|
|||||||
return new QTableMetaData()
|
return new QTableMetaData()
|
||||||
.withName("person")
|
.withName("person")
|
||||||
.withLabel("Person")
|
.withLabel("Person")
|
||||||
|
.withRecordLabelFormat("%s %s")
|
||||||
|
.withRecordLabelFields("firstName", "lastName")
|
||||||
.withBackendName(defineBackend().getName())
|
.withBackendName(defineBackend().getName())
|
||||||
.withPrimaryKeyField("id")
|
.withPrimaryKeyField("id")
|
||||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
@ -189,6 +195,7 @@ public class TestUtils
|
|||||||
.withField(new QFieldMetaData("firstName", QFieldType.STRING).withBackendName("first_name"))
|
.withField(new QFieldMetaData("firstName", QFieldType.STRING).withBackendName("first_name"))
|
||||||
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withBackendName("last_name"))
|
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withBackendName("last_name"))
|
||||||
.withField(new QFieldMetaData("birthDate", QFieldType.DATE).withBackendName("birth_date"))
|
.withField(new QFieldMetaData("birthDate", QFieldType.DATE).withBackendName("birth_date"))
|
||||||
|
.withField(new QFieldMetaData("partnerPersonId", QFieldType.INTEGER).withBackendName("partner_person_id").withPossibleValueSourceName("person"))
|
||||||
.withField(new QFieldMetaData("email", QFieldType.STRING));
|
.withField(new QFieldMetaData("email", QFieldType.STRING));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +275,22 @@ public class TestUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static QPossibleValueSource definePossibleValueSourcePerson()
|
||||||
|
{
|
||||||
|
return (new QPossibleValueSource()
|
||||||
|
.withName("person")
|
||||||
|
.withType(QPossibleValueSourceType.TABLE)
|
||||||
|
.withTableName("person")
|
||||||
|
.withValueFormatAndFields(PVSValueFormatAndFields.LABEL_PARENS_ID)
|
||||||
|
.withOrderByField("id")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Define a process with just one step that sleeps
|
** Define a process with just one step that sleeps
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -29,7 +29,8 @@ CREATE TABLE person
|
|||||||
first_name VARCHAR(80) NOT NULL,
|
first_name VARCHAR(80) NOT NULL,
|
||||||
last_name VARCHAR(80) NOT NULL,
|
last_name VARCHAR(80) NOT NULL,
|
||||||
birth_date DATE,
|
birth_date DATE,
|
||||||
email VARCHAR(250) NOT NULL
|
email VARCHAR(250) NOT NULL,
|
||||||
|
partner_person_id INT
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com');
|
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com');
|
||||||
|
Reference in New Issue
Block a user