mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +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)
|
||||
{
|
||||
@ -122,6 +150,16 @@ public class QPossibleValueTranslator
|
||||
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;
|
||||
if(possibleValueSource.getType().equals(QPossibleValueSourceType.ENUM))
|
||||
{
|
||||
@ -129,15 +167,15 @@ public class QPossibleValueTranslator
|
||||
}
|
||||
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.TABLE))
|
||||
{
|
||||
resultValue = translatePossibleValueTable(field, value, possibleValueSource);
|
||||
resultValue = translatePossibleValueTable(value, possibleValueSource);
|
||||
}
|
||||
else if(possibleValueSource.getType().equals(QPossibleValueSourceType.CUSTOM))
|
||||
{
|
||||
resultValue = translatePossibleValueCustom(field, value, possibleValueSource);
|
||||
resultValue = translatePossibleValueCustom(value, possibleValueSource);
|
||||
}
|
||||
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)
|
||||
@ -151,7 +189,7 @@ public class QPossibleValueTranslator
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** do translation for an enum-type PVS
|
||||
*******************************************************************************/
|
||||
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 //
|
||||
@ -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
|
||||
{
|
||||
@ -208,7 +246,7 @@ public class QPossibleValueTranslator
|
||||
}
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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.values.QCustomPossibleValueProvider;
|
||||
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.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||
@ -715,6 +716,8 @@ public class QInstanceValidator
|
||||
case ENUM ->
|
||||
{
|
||||
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(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(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."))
|
||||
{
|
||||
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 ->
|
||||
{
|
||||
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(!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."))
|
||||
{
|
||||
|
@ -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.List;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
|
||||
|
||||
@ -49,7 +50,8 @@ public class QPossibleValueSource
|
||||
// for type = TABLE //
|
||||
//////////////////////
|
||||
private String tableName;
|
||||
// todo - override labelFormat & labelFields?
|
||||
private List<String> searchFields;
|
||||
private List<QFilterOrderBy> orderByFields;
|
||||
|
||||
/////////////////////
|
||||
// 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
|
||||
**
|
||||
|
@ -364,7 +364,17 @@ public class MemoryRecordStore
|
||||
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);
|
||||
}
|
||||
|
@ -454,8 +454,15 @@ public class ValueUtils
|
||||
return (null);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Instant.parse(s);
|
||||
}
|
||||
catch(DateTimeParseException e)
|
||||
{
|
||||
return tryAlternativeInstantParsing(s, e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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.tables.query.QCriteriaOperator;
|
||||
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.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
@ -793,10 +794,14 @@ class QInstanceValidatorTest
|
||||
assertValidationFailureReasons((qInstance) -> {
|
||||
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||
possibleValueSource.setTableName("person");
|
||||
possibleValueSource.setSearchFields(List.of("id"));
|
||||
possibleValueSource.setOrderByFields(List.of(new QFilterOrderBy("id")));
|
||||
possibleValueSource.setCustomCodeReference(new QCodeReference());
|
||||
possibleValueSource.setEnumValues(null);
|
||||
},
|
||||
"should not have a tableName",
|
||||
"should not have searchFields",
|
||||
"should not have orderByFields",
|
||||
"should not have a customCodeReference",
|
||||
"is missing enum values");
|
||||
|
||||
@ -815,15 +820,22 @@ class QInstanceValidatorTest
|
||||
assertValidationFailureReasons((qInstance) -> {
|
||||
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||
possibleValueSource.setTableName(null);
|
||||
possibleValueSource.setSearchFields(null);
|
||||
possibleValueSource.setOrderByFields(new ArrayList<>());
|
||||
possibleValueSource.setCustomCodeReference(new QCodeReference());
|
||||
possibleValueSource.setEnumValues(List.of(new QPossibleValue<>("test")));
|
||||
},
|
||||
"should not have enum values",
|
||||
"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"),
|
||||
"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) -> {
|
||||
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
|
||||
possibleValueSource.setTableName("person");
|
||||
possibleValueSource.setSearchFields(List.of("id"));
|
||||
possibleValueSource.setOrderByFields(List.of(new QFilterOrderBy("id")));
|
||||
possibleValueSource.setCustomCodeReference(null);
|
||||
possibleValueSource.setEnumValues(List.of(new QPossibleValue<>("test")));
|
||||
},
|
||||
"should not have enum values",
|
||||
"should not have a tableName",
|
||||
"should not have searchFields",
|
||||
"should not have orderByFields",
|
||||
"is missing a customCodeReference");
|
||||
|
||||
assertValidationFailureReasons((qInstance) -> qInstance.getPossibleValueSource(TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM).setCustomCodeReference(new QCodeReference()),
|
||||
|
@ -331,7 +331,9 @@ public class TestUtils
|
||||
return new QPossibleValueSource()
|
||||
.withName(POSSIBLE_VALUE_SOURCE_SHAPE)
|
||||
.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.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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.QueryAction;
|
||||
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.exceptions.QAuthenticationException;
|
||||
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.update.UpdateInput;
|
||||
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.RenderWidgetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.modules.authentication.Auth0AuthenticationModule;
|
||||
@ -277,6 +282,7 @@ public class QJavalinImplementation
|
||||
get("/count", QJavalinImplementation::dataCount);
|
||||
get("/export", QJavalinImplementation::dataExportWithoutFilename);
|
||||
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.
|
||||
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"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@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.sql.Connection;
|
||||
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.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.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.QCodeType;
|
||||
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.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields;
|
||||
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.QFrontendStepMetaData;
|
||||
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.QProcessMetaData;
|
||||
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.QueryManager;
|
||||
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
||||
@ -123,6 +126,7 @@ public class TestUtils
|
||||
qInstance.addProcess(defineProcessSimpleSleep());
|
||||
qInstance.addProcess(defineProcessScreenThenSleep());
|
||||
qInstance.addProcess(defineProcessSimpleThrow());
|
||||
qInstance.addPossibleValueSource(definePossibleValueSourcePerson());
|
||||
defineWidgets(qInstance);
|
||||
return (qInstance);
|
||||
}
|
||||
@ -181,6 +185,8 @@ public class TestUtils
|
||||
return new QTableMetaData()
|
||||
.withName("person")
|
||||
.withLabel("Person")
|
||||
.withRecordLabelFormat("%s %s")
|
||||
.withRecordLabelFields("firstName", "lastName")
|
||||
.withBackendName(defineBackend().getName())
|
||||
.withPrimaryKeyField("id")
|
||||
.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("lastName", QFieldType.STRING).withBackendName("last_name"))
|
||||
.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));
|
||||
}
|
||||
|
||||
@ -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
|
||||
*******************************************************************************/
|
||||
|
@ -29,7 +29,8 @@ CREATE TABLE person
|
||||
first_name VARCHAR(80) NOT NULL,
|
||||
last_name VARCHAR(80) NOT NULL,
|
||||
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');
|
||||
|
Reference in New Issue
Block a user