mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Merge branch 'feature/CE-1107-add-day-by-day-views-for-the' into dev
This commit is contained in:
@ -42,6 +42,7 @@ import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.QWidgetData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.WidgetDropdownData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.WidgetDropdownType;
|
||||
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.utils.CollectionUtils;
|
||||
@ -72,80 +73,104 @@ public abstract class AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
protected boolean setupDropdowns(RenderWidgetInput input, QWidgetMetaData metaData, QWidgetData widgetData) throws QException
|
||||
{
|
||||
List<List<Map<String, String>>> pvsData = new ArrayList<>();
|
||||
List<String> pvsLabels = new ArrayList<>();
|
||||
List<String> pvsNames = new ArrayList<>();
|
||||
List<List<Map<String, String>>> dataList = new ArrayList<>();
|
||||
List<String> labelList = new ArrayList<>();
|
||||
List<String> nameList = new ArrayList<>();
|
||||
List<String> missingRequiredSelections = new ArrayList<>();
|
||||
for(WidgetDropdownData dropdownData : CollectionUtils.nonNullList(metaData.getDropdowns()))
|
||||
{
|
||||
String possibleValueSourceName = dropdownData.getPossibleValueSourceName();
|
||||
QPossibleValueSource possibleValueSource = input.getInstance().getPossibleValueSource(possibleValueSourceName);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// this looks complicated, but is just look for a label in the dropdown data and if found use it, //
|
||||
// otherwise look for label in PVS and if found use that, otherwise just use the PVS name //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
String pvsLabel = dropdownData.getLabel() != null ? dropdownData.getLabel() : (possibleValueSource.getLabel() != null ? possibleValueSource.getLabel() : possibleValueSourceName);
|
||||
pvsLabels.add(pvsLabel);
|
||||
pvsNames.add(possibleValueSourceName);
|
||||
|
||||
SearchPossibleValueSourceInput pvsInput = new SearchPossibleValueSourceInput();
|
||||
pvsInput.setPossibleValueSourceName(possibleValueSourceName);
|
||||
|
||||
if(dropdownData.getForeignKeyFieldName() != null)
|
||||
if(WidgetDropdownType.DATE_PICKER.equals(dropdownData.getType()))
|
||||
{
|
||||
////////////////////////////////////////
|
||||
// look for an id in the query params //
|
||||
////////////////////////////////////////
|
||||
Integer id = null;
|
||||
if(input.getQueryParams() != null && input.getQueryParams().containsKey("id") && StringUtils.hasContent(input.getQueryParams().get("id")))
|
||||
String name = dropdownData.getName();
|
||||
nameList.add(name);
|
||||
labelList.add(dropdownData.getLabel());
|
||||
dataList.add(new ArrayList<>());
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// sure that something has been selected, and if not, display a message that a selection needs made //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(dropdownData.getIsRequired())
|
||||
{
|
||||
id = Integer.parseInt(input.getQueryParams().get("id"));
|
||||
}
|
||||
if(id != null)
|
||||
{
|
||||
pvsInput.setDefaultQueryFilter(new QQueryFilter().withCriteria(
|
||||
new QFilterCriteria(
|
||||
dropdownData.getForeignKeyFieldName(),
|
||||
QCriteriaOperator.EQUALS,
|
||||
id)));
|
||||
if(!input.getQueryParams().containsKey(name) || !StringUtils.hasContent(input.getQueryParams().get(name)))
|
||||
{
|
||||
missingRequiredSelections.add(dropdownData.getLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(pvsInput);
|
||||
|
||||
List<Map<String, String>> dropdownOptionList = new ArrayList<>();
|
||||
pvsData.add(dropdownOptionList);
|
||||
|
||||
//////////////////////////////////////////
|
||||
// sort results, dedupe, and add to map //
|
||||
//////////////////////////////////////////
|
||||
Set<String> exists = new HashSet<>();
|
||||
output.getResults().removeIf(pvs -> !exists.add(pvs.getLabel()));
|
||||
for(QPossibleValue<?> possibleValue : output.getResults())
|
||||
else
|
||||
{
|
||||
dropdownOptionList.add(MapBuilder.of(
|
||||
"id", String.valueOf(possibleValue.getId()),
|
||||
"label", possibleValue.getLabel()
|
||||
));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// because we know the dropdowns and what the field names will be when something is selected, we can make //
|
||||
// sure that something has been selected, and if not, display a message that a selection needs made //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(dropdownData.getIsRequired())
|
||||
{
|
||||
if(!input.getQueryParams().containsKey(possibleValueSourceName) || !StringUtils.hasContent(input.getQueryParams().get(possibleValueSourceName)))
|
||||
String possibleValueSourceName = dropdownData.getPossibleValueSourceName();
|
||||
if(possibleValueSourceName != null)
|
||||
{
|
||||
missingRequiredSelections.add(pvsLabel);
|
||||
QPossibleValueSource possibleValueSource = input.getInstance().getPossibleValueSource(possibleValueSourceName);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// this looks complicated, but is just look for a label in the dropdown data and if found use it, //
|
||||
// otherwise look for label in PVS and if found use that, otherwise just use the PVS name //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
String pvsLabel = dropdownData.getLabel() != null ? dropdownData.getLabel() : (possibleValueSource.getLabel() != null ? possibleValueSource.getLabel() : possibleValueSourceName);
|
||||
labelList.add(pvsLabel);
|
||||
nameList.add(possibleValueSourceName);
|
||||
|
||||
SearchPossibleValueSourceInput pvsInput = new SearchPossibleValueSourceInput();
|
||||
pvsInput.setPossibleValueSourceName(possibleValueSourceName);
|
||||
|
||||
if(dropdownData.getForeignKeyFieldName() != null)
|
||||
{
|
||||
////////////////////////////////////////
|
||||
// look for an id in the query params //
|
||||
////////////////////////////////////////
|
||||
Integer id = null;
|
||||
if(input.getQueryParams() != null && input.getQueryParams().containsKey("id") && StringUtils.hasContent(input.getQueryParams().get("id")))
|
||||
{
|
||||
id = Integer.parseInt(input.getQueryParams().get("id"));
|
||||
}
|
||||
if(id != null)
|
||||
{
|
||||
pvsInput.setDefaultQueryFilter(new QQueryFilter().withCriteria(
|
||||
new QFilterCriteria(
|
||||
dropdownData.getForeignKeyFieldName(),
|
||||
QCriteriaOperator.EQUALS,
|
||||
id)));
|
||||
}
|
||||
}
|
||||
|
||||
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(pvsInput);
|
||||
|
||||
List<Map<String, String>> dropdownOptionList = new ArrayList<>();
|
||||
dataList.add(dropdownOptionList);
|
||||
|
||||
//////////////////////////////////////////
|
||||
// sort results, dedupe, and add to map //
|
||||
//////////////////////////////////////////
|
||||
Set<String> exists = new HashSet<>();
|
||||
output.getResults().removeIf(pvs -> !exists.add(pvs.getLabel()));
|
||||
for(QPossibleValue<?> possibleValue : output.getResults())
|
||||
{
|
||||
dropdownOptionList.add(MapBuilder.of(
|
||||
"id", String.valueOf(possibleValue.getId()),
|
||||
"label", possibleValue.getLabel()
|
||||
));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// because we know the dropdowns and what the field names will be when something is selected, we can make //
|
||||
// sure that something has been selected, and if not, display a message that a selection needs made //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(dropdownData.getIsRequired())
|
||||
{
|
||||
if(!input.getQueryParams().containsKey(possibleValueSourceName) || !StringUtils.hasContent(input.getQueryParams().get(possibleValueSourceName)))
|
||||
{
|
||||
missingRequiredSelections.add(pvsLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
widgetData.setDropdownNameList(pvsNames);
|
||||
widgetData.setDropdownLabelList(pvsLabels);
|
||||
widgetData.setDropdownDataList(pvsData);
|
||||
widgetData.setDropdownNameList(nameList);
|
||||
widgetData.setDropdownLabelList(labelList);
|
||||
widgetData.setDropdownDataList(dataList);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// if there are any missing required dropdowns, build up a message to display //
|
||||
|
@ -47,6 +47,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -79,9 +80,11 @@ public class ReplaceAction extends AbstractQActionFunction<ReplaceInput, Replace
|
||||
|
||||
try
|
||||
{
|
||||
QTableMetaData table = input.getTable();
|
||||
UniqueKey uniqueKey = input.getKey();
|
||||
String primaryKeyField = table.getPrimaryKeyField();
|
||||
QTableMetaData table = input.getTable();
|
||||
UniqueKey uniqueKey = input.getKey();
|
||||
String primaryKeyField = table.getPrimaryKeyField();
|
||||
boolean allowNullKeyValuesToEqual = BooleanUtils.isTrue(input.getAllowNullKeyValuesToEqual());
|
||||
|
||||
if(transaction == null)
|
||||
{
|
||||
transaction = QBackendTransaction.openFor(new InsertInput(input.getTableName()));
|
||||
@ -98,10 +101,11 @@ public class ReplaceAction extends AbstractQActionFunction<ReplaceInput, Replace
|
||||
// originally it was thought that we'd need to pass the filter in here //
|
||||
// but, it's been decided not to. the filter only applies to what we can delete //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
Map<List<Serializable>, Serializable> existingKeys = UniqueKeyHelper.getExistingKeys(transaction, table, page, uniqueKey);
|
||||
Map<List<Serializable>, Serializable> existingKeys = UniqueKeyHelper.getExistingKeys(transaction, table, page, uniqueKey, allowNullKeyValuesToEqual);
|
||||
|
||||
for(QRecord record : page)
|
||||
{
|
||||
Optional<List<Serializable>> keyValues = UniqueKeyHelper.getKeyValues(table, uniqueKey, record);
|
||||
Optional<List<Serializable>> keyValues = UniqueKeyHelper.getKeyValues(table, uniqueKey, record, allowNullKeyValuesToEqual);
|
||||
if(keyValues.isPresent())
|
||||
{
|
||||
if(existingKeys.containsKey(keyValues.get()))
|
||||
|
@ -54,7 +54,7 @@ public class UniqueKeyHelper
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static Map<List<Serializable>, Serializable> getExistingKeys(QBackendTransaction transaction, QTableMetaData table, List<QRecord> recordList, UniqueKey uniqueKey) throws QException
|
||||
public static Map<List<Serializable>, Serializable> getExistingKeys(QBackendTransaction transaction, QTableMetaData table, List<QRecord> recordList, UniqueKey uniqueKey, boolean allowNullKeyValuesToEqual) throws QException
|
||||
{
|
||||
List<String> ukFieldNames = uniqueKey.getFieldNames();
|
||||
Map<List<Serializable>, Serializable> existingRecords = new HashMap<>();
|
||||
@ -112,7 +112,7 @@ public class UniqueKeyHelper
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
for(QRecord record : queryOutput.getRecords())
|
||||
{
|
||||
Optional<List<Serializable>> keyValues = getKeyValues(table, uniqueKey, record);
|
||||
Optional<List<Serializable>> keyValues = getKeyValues(table, uniqueKey, record, allowNullKeyValuesToEqual);
|
||||
if(keyValues.isPresent())
|
||||
{
|
||||
existingRecords.put(keyValues.get(), record.getValue(table.getPrimaryKeyField()));
|
||||
@ -128,7 +128,17 @@ public class UniqueKeyHelper
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static Optional<List<Serializable>> getKeyValues(QTableMetaData table, UniqueKey uniqueKey, QRecord record)
|
||||
public static Map<List<Serializable>, Serializable> getExistingKeys(QBackendTransaction transaction, QTableMetaData table, List<QRecord> recordList, UniqueKey uniqueKey) throws QException
|
||||
{
|
||||
return (getExistingKeys(transaction, table, recordList, uniqueKey, false));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static Optional<List<Serializable>> getKeyValues(QTableMetaData table, UniqueKey uniqueKey, QRecord record, boolean allowNullKeyValuesToEqual)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -138,7 +148,19 @@ public class UniqueKeyHelper
|
||||
QFieldMetaData field = table.getField(fieldName);
|
||||
Serializable value = record.getValue(fieldName);
|
||||
Serializable typedValue = ValueUtils.getValueAsFieldType(field.getType(), value);
|
||||
keyValues.add(typedValue == null ? new NullUniqueKeyValue() : typedValue);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// if null value, look at flag to determine if a null should be used (which will //
|
||||
// allow keys to match), or a NullUniqueKeyValue, (which will never match) //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
if(typedValue == null)
|
||||
{
|
||||
keyValues.add(allowNullKeyValuesToEqual ? null : new NullUniqueKeyValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
keyValues.add(typedValue);
|
||||
}
|
||||
}
|
||||
return (Optional.of(keyValues));
|
||||
}
|
||||
@ -150,6 +172,16 @@ public class UniqueKeyHelper
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static Optional<List<Serializable>> getKeyValues(QTableMetaData table, UniqueKey uniqueKey, QRecord record)
|
||||
{
|
||||
return (getKeyValues(table, uniqueKey, record, false));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** To make a list of unique key values here behave like they do in an RDBMS
|
||||
** (which is what we're trying to mimic - which is - 2 null values in a field
|
||||
|
@ -39,7 +39,8 @@ public class ReplaceInput extends AbstractTableActionInput
|
||||
private UniqueKey key;
|
||||
private List<QRecord> records;
|
||||
private QQueryFilter filter;
|
||||
private boolean performDeletes = true;
|
||||
private boolean performDeletes = true;
|
||||
private boolean allowNullKeyValuesToEqual = false;
|
||||
|
||||
private boolean omitDmlAudit = false;
|
||||
|
||||
@ -239,4 +240,35 @@ public class ReplaceInput extends AbstractTableActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for allowNullKeyValuesToEqual
|
||||
*******************************************************************************/
|
||||
public boolean getAllowNullKeyValuesToEqual()
|
||||
{
|
||||
return (this.allowNullKeyValuesToEqual);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for allowNullKeyValuesToEqual
|
||||
*******************************************************************************/
|
||||
public void setAllowNullKeyValuesToEqual(boolean allowNullKeyValuesToEqual)
|
||||
{
|
||||
this.allowNullKeyValuesToEqual = allowNullKeyValuesToEqual;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for allowNullKeyValuesToEqual
|
||||
*******************************************************************************/
|
||||
public ReplaceInput withAllowNullKeyValuesToEqual(boolean allowNullKeyValuesToEqual)
|
||||
{
|
||||
this.allowNullKeyValuesToEqual = allowNullKeyValuesToEqual;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.dashboard.widgets;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Model containing datastructure expected by frontend alert widget
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AlertData extends QWidgetData
|
||||
{
|
||||
public enum AlertType
|
||||
{
|
||||
ERROR,
|
||||
SUCCESS,
|
||||
WARNING
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String html;
|
||||
private AlertType alertType;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AlertData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AlertData(AlertType alertType, String html)
|
||||
{
|
||||
setHtml(html);
|
||||
setAlertType(alertType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getType()
|
||||
{
|
||||
return WidgetType.ALERT.getType();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for html
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getHtml()
|
||||
{
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for html
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setHtml(String html)
|
||||
{
|
||||
this.html = html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for html
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AlertData withHtml(String html)
|
||||
{
|
||||
this.html = html;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for alertType
|
||||
*******************************************************************************/
|
||||
public AlertType getAlertType()
|
||||
{
|
||||
return (this.alertType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for alertType
|
||||
*******************************************************************************/
|
||||
public void setAlertType(AlertType alertType)
|
||||
{
|
||||
this.alertType = alertType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for alertType
|
||||
*******************************************************************************/
|
||||
public AlertData withAlertType(AlertType alertType)
|
||||
{
|
||||
this.alertType = alertType;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ package com.kingsrook.qqq.backend.core.model.dashboard.widgets;
|
||||
*******************************************************************************/
|
||||
public enum WidgetType
|
||||
{
|
||||
ALERT("alert"),
|
||||
BAR_CHART("barChart"),
|
||||
CHART("chart"),
|
||||
CHILD_RECORD_LIST("childRecordList"),
|
||||
|
@ -28,6 +28,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.dashboard;
|
||||
*******************************************************************************/
|
||||
public class WidgetDropdownData
|
||||
{
|
||||
private String name;
|
||||
private String possibleValueSourceName;
|
||||
private String foreignKeyFieldName;
|
||||
private String label;
|
||||
@ -44,6 +45,9 @@ public class WidgetDropdownData
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private String labelForNullValue;
|
||||
|
||||
private WidgetDropdownType type = WidgetDropdownType.POSSIBLE_VALUE_SOURCE;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for possibleValueSourceName
|
||||
@ -366,4 +370,65 @@ public class WidgetDropdownData
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
*******************************************************************************/
|
||||
public WidgetDropdownType getType()
|
||||
{
|
||||
return (this.type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
*******************************************************************************/
|
||||
public void setType(WidgetDropdownType type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for type
|
||||
*******************************************************************************/
|
||||
public WidgetDropdownData withType(WidgetDropdownType type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return (this.name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for name
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for name
|
||||
*******************************************************************************/
|
||||
public WidgetDropdownData withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Possible types for widget dropdowns
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum WidgetDropdownType
|
||||
{
|
||||
POSSIBLE_VALUE_SOURCE,
|
||||
DATE_PICKER
|
||||
}
|
@ -43,7 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for ReplaceAction
|
||||
** Unit test for ReplaceAction
|
||||
*******************************************************************************/
|
||||
class ReplaceActionTest extends BaseTest
|
||||
{
|
||||
@ -157,6 +157,134 @@ class ReplaceActionTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testTwoKeysWithNullsNotMatchingAllowingDelete() throws QException
|
||||
{
|
||||
String tableName = TestUtils.TABLE_NAME_TWO_KEYS;
|
||||
|
||||
////////////////////////////////
|
||||
// start with these 2 records //
|
||||
////////////////////////////////
|
||||
new InsertAction().execute(new InsertInput(tableName).withRecords(List.of(
|
||||
new QRecord().withValue("key1", 1).withValue("key2", 2),
|
||||
new QRecord().withValue("key1", 3)
|
||||
)));
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// now do a replace action that just updates them //
|
||||
////////////////////////////////////////////////////
|
||||
List<QRecord> newThings = List.of(
|
||||
new QRecord().withValue("key1", 1).withValue("key2", 2),
|
||||
new QRecord().withValue("key1", 3)
|
||||
);
|
||||
|
||||
//////////////////////////////
|
||||
// replace allowing deletes //
|
||||
//////////////////////////////
|
||||
ReplaceInput replaceInput = new ReplaceInput();
|
||||
replaceInput.setTableName(tableName);
|
||||
replaceInput.setKey(new UniqueKey("key1", "key2"));
|
||||
replaceInput.setOmitDmlAudit(true);
|
||||
replaceInput.setRecords(newThings);
|
||||
replaceInput.setFilter(null);
|
||||
ReplaceOutput replaceOutput = new ReplaceAction().execute(replaceInput);
|
||||
|
||||
assertEquals(1, replaceOutput.getInsertOutput().getRecords().size());
|
||||
assertEquals(1, replaceOutput.getUpdateOutput().getRecords().size());
|
||||
assertEquals(1, replaceOutput.getDeleteOutput().getDeletedRecordCount());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testTwoKeysWithNullsNotMatchingNotAllowingDelete() throws QException
|
||||
{
|
||||
String tableName = TestUtils.TABLE_NAME_TWO_KEYS;
|
||||
|
||||
////////////////////////////////
|
||||
// start with these 2 records //
|
||||
////////////////////////////////
|
||||
new InsertAction().execute(new InsertInput(tableName).withRecords(List.of(
|
||||
new QRecord().withValue("key1", 1).withValue("key2", 2),
|
||||
new QRecord().withValue("key1", 3)
|
||||
)));
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// now do a replace action that just updates them //
|
||||
////////////////////////////////////////////////////
|
||||
List<QRecord> newThings = List.of(
|
||||
new QRecord().withValue("key1", 1).withValue("key2", 2),
|
||||
new QRecord().withValue("key1", 3)
|
||||
);
|
||||
|
||||
/////////////////////////////////
|
||||
// replace disallowing deletes //
|
||||
/////////////////////////////////
|
||||
ReplaceInput replaceInput = new ReplaceInput();
|
||||
replaceInput.setTableName(tableName);
|
||||
replaceInput.setKey(new UniqueKey("key1", "key2"));
|
||||
replaceInput.setOmitDmlAudit(true);
|
||||
replaceInput.setRecords(newThings);
|
||||
replaceInput.setFilter(null);
|
||||
replaceInput.setPerformDeletes(false);
|
||||
ReplaceOutput replaceOutput = new ReplaceAction().execute(replaceInput);
|
||||
|
||||
assertEquals(1, replaceOutput.getInsertOutput().getRecords().size());
|
||||
assertEquals(1, replaceOutput.getUpdateOutput().getRecords().size());
|
||||
assertNull(replaceOutput.getDeleteOutput());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testTwoKeysWithNullMatching() throws QException
|
||||
{
|
||||
String tableName = TestUtils.TABLE_NAME_TWO_KEYS;
|
||||
|
||||
////////////////////////////////
|
||||
// start with these 2 records //
|
||||
////////////////////////////////
|
||||
new InsertAction().execute(new InsertInput(tableName).withRecords(List.of(
|
||||
new QRecord().withValue("key1", 1).withValue("key2", 2),
|
||||
new QRecord().withValue("key1", 3)
|
||||
)));
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// now do a replace action that just updates them //
|
||||
////////////////////////////////////////////////////
|
||||
List<QRecord> newThings = List.of(
|
||||
new QRecord().withValue("key1", 1).withValue("key2", 2),
|
||||
new QRecord().withValue("key1", 3)
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// replace treating null key values as equal //
|
||||
///////////////////////////////////////////////
|
||||
ReplaceInput replaceInput = new ReplaceInput();
|
||||
replaceInput.setTableName(tableName);
|
||||
replaceInput.setKey(new UniqueKey("key1", "key2"));
|
||||
replaceInput.setOmitDmlAudit(true);
|
||||
replaceInput.setRecords(newThings);
|
||||
replaceInput.setFilter(null);
|
||||
replaceInput.setAllowNullKeyValuesToEqual(true);
|
||||
ReplaceOutput replaceOutput = new ReplaceAction().execute(replaceInput);
|
||||
|
||||
assertEquals(0, replaceOutput.getInsertOutput().getRecords().size());
|
||||
assertEquals(2, replaceOutput.getUpdateOutput().getRecords().size());
|
||||
assertEquals(0, replaceOutput.getDeleteOutput().getDeletedRecordCount());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -297,4 +425,4 @@ class ReplaceActionTest extends BaseTest
|
||||
return new GetAction().executeForRecord(new GetInput(TestUtils.TABLE_NAME_PERSON_MEMORY).withUniqueKey(Map.of("firstName", firstName, "lastName", lastName))).getValueInteger("noOfShoes");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ public class TestUtils
|
||||
public static final String APP_NAME_PEOPLE = "peopleApp";
|
||||
public static final String APP_NAME_MISCELLANEOUS = "miscellaneous";
|
||||
|
||||
public static final String TABLE_NAME_TWO_KEYS = "twoKeys";
|
||||
public static final String TABLE_NAME_PERSON = "person";
|
||||
public static final String TABLE_NAME_SHAPE = "shape";
|
||||
public static final String TABLE_NAME_SHAPE_CACHE = "shapeCache";
|
||||
@ -196,6 +197,7 @@ public class TestUtils
|
||||
qInstance.addBackend(defineMemoryBackend());
|
||||
|
||||
qInstance.addTable(defineTablePerson());
|
||||
qInstance.addTable(defineTableTwoKeys());
|
||||
qInstance.addTable(definePersonFileTable());
|
||||
qInstance.addTable(definePersonMemoryTable());
|
||||
qInstance.addTable(definePersonMemoryCacheTable());
|
||||
@ -545,6 +547,24 @@ public class TestUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Define the 'two key' table used in standard tests.
|
||||
*******************************************************************************/
|
||||
public static QTableMetaData defineTableTwoKeys()
|
||||
{
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME_TWO_KEYS)
|
||||
.withLabel("Two Keys")
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withPrimaryKeyField("id")
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||
.withUniqueKey(new UniqueKey("key1", "key2"))
|
||||
.withField(new QFieldMetaData("key1", QFieldType.INTEGER))
|
||||
.withField(new QFieldMetaData("key2", QFieldType.INTEGER));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Define the 'person' table used in standard tests.
|
||||
*******************************************************************************/
|
||||
@ -791,6 +811,26 @@ public class TestUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Define a table with unique key where one is nullable
|
||||
*******************************************************************************/
|
||||
public static QTableMetaData defineTwoKeyTable()
|
||||
{
|
||||
return (new QTableMetaData()
|
||||
.withName(TABLE_NAME_BASEPULL)
|
||||
.withLabel("Basepull Test")
|
||||
.withPrimaryKeyField("id")
|
||||
.withBackendName(MEMORY_BACKEND_NAME)
|
||||
.withFields(TestUtils.defineTablePerson().getFields()))
|
||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withBackendName("create_date").withIsEditable(false))
|
||||
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withBackendName("modify_date").withIsEditable(false))
|
||||
.withField(new QFieldMetaData(BASEPULL_KEY_FIELD_NAME, QFieldType.STRING).withBackendName("process_name").withIsRequired(true))
|
||||
.withField(new QFieldMetaData(BASEPULL_LAST_RUN_TIME_FIELD_NAME, QFieldType.DATE_TIME).withBackendName("last_run_time").withIsRequired(true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Define a basepullTable
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user