mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Add joins and ChildRecordList widget
This commit is contained in:
@ -22,11 +22,15 @@
|
|||||||
package com.kingsrook.qqq.backend.core.actions.dashboard;
|
package com.kingsrook.qqq.backend.core.actions.dashboard;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
|
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -44,6 +48,18 @@ public class RenderWidgetAction
|
|||||||
ActionHelper.validateSession(input);
|
ActionHelper.validateSession(input);
|
||||||
|
|
||||||
AbstractWidgetRenderer widgetRenderer = QCodeLoader.getAdHoc(AbstractWidgetRenderer.class, input.getWidgetMetaData().getCodeReference());
|
AbstractWidgetRenderer widgetRenderer = QCodeLoader.getAdHoc(AbstractWidgetRenderer.class, input.getWidgetMetaData().getCodeReference());
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
// move default values from meta data into this render input //
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
if(input.getWidgetMetaData() instanceof QWidgetMetaData widgetMetaData)
|
||||||
|
{
|
||||||
|
for(Map.Entry<String, Serializable> entry : widgetMetaData.getDefaultValues().entrySet())
|
||||||
|
{
|
||||||
|
input.getQueryParams().putIfAbsent(entry.getKey(), ValueUtils.getValueAsString(entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (widgetRenderer.render(input));
|
return (widgetRenderer.render(input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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.dashboard.widgets;
|
||||||
|
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.dashboard.AbstractWidgetRenderer;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.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.widgets.RenderWidgetInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.ChildRecordListData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Generic widget for display a list of child records.
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ChildRecordListRenderer extends AbstractWidgetRenderer
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QWidgetMetaData defineWidgetFromJoin(QJoinMetaData join)
|
||||||
|
{
|
||||||
|
return (new QWidgetMetaData()
|
||||||
|
.withName(join.getName())
|
||||||
|
.withCodeReference(new QCodeReference(ChildRecordListRenderer.class, null))
|
||||||
|
.withType(WidgetType.CHILD_RECORD_LIST.getType())
|
||||||
|
.withDefaultValue("joinName", join.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Override
|
||||||
|
public RenderWidgetOutput render(RenderWidgetInput input) throws QException
|
||||||
|
{
|
||||||
|
String widgetLabel = input.getQueryParams().get("widgetLabel");
|
||||||
|
String joinName = input.getQueryParams().get("joinName");
|
||||||
|
QJoinMetaData join = input.getInstance().getJoin(joinName);
|
||||||
|
String id = input.getQueryParams().get("id");
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
// fetch the record that we're getting children for. //
|
||||||
|
// e.g., the left-side of the join, with the input id //
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
GetInput getInput = new GetInput(input.getInstance());
|
||||||
|
getInput.setSession(input.getSession());
|
||||||
|
getInput.setTableName(join.getLeftTable());
|
||||||
|
getInput.setPrimaryKey(id);
|
||||||
|
GetOutput getOutput = new GetAction().execute(getInput);
|
||||||
|
QRecord record = getOutput.getRecord();
|
||||||
|
|
||||||
|
if(record == null)
|
||||||
|
{
|
||||||
|
QTableMetaData table = input.getInstance().getTable(join.getLeftTable());
|
||||||
|
throw (new QNotFoundException("Could not find " + (table == null ? "" : table.getLabel()) + " with primary key " + id));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// set up the query - for the table on the right side of the join //
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
QQueryFilter filter = new QQueryFilter();
|
||||||
|
for(JoinOn joinOn : join.getJoinOns())
|
||||||
|
{
|
||||||
|
filter.addCriteria(new QFilterCriteria(joinOn.getRightField(), QCriteriaOperator.EQUALS, List.of(record.getValue(joinOn.getLeftField()))));
|
||||||
|
}
|
||||||
|
filter.setOrderBys(join.getOrderBys());
|
||||||
|
|
||||||
|
QueryInput queryInput = new QueryInput(input.getInstance());
|
||||||
|
queryInput.setSession(input.getSession());
|
||||||
|
queryInput.setTableName(join.getRightTable());
|
||||||
|
queryInput.setShouldTranslatePossibleValues(true);
|
||||||
|
queryInput.setShouldGenerateDisplayValues(true);
|
||||||
|
queryInput.setFilter(filter);
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
|
||||||
|
QTableMetaData table = input.getInstance().getTable(join.getRightTable());
|
||||||
|
String tablePath = input.getInstance().getTablePath(input, table.getName());
|
||||||
|
String viewAllLink = tablePath + "?filter=" + URLEncoder.encode(JsonUtils.toJson(filter), Charset.defaultCharset());
|
||||||
|
|
||||||
|
return (new RenderWidgetOutput(new ChildRecordListData(widgetLabel, queryOutput, table, tablePath, viewAllLink)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -285,7 +285,7 @@ public class QInstanceValidator
|
|||||||
{
|
{
|
||||||
for(QFieldSection section : table.getSections())
|
for(QFieldSection section : table.getSections())
|
||||||
{
|
{
|
||||||
validateFieldSection(table, section, fieldNamesInSections);
|
validateTableSection(qInstance, table, section, fieldNamesInSections);
|
||||||
if(section.getTier().equals(Tier.T1))
|
if(section.getTier().equals(Tier.T1))
|
||||||
{
|
{
|
||||||
assertCondition(tier1Section == null, "Table " + tableName + " has more than 1 section listed as Tier 1");
|
assertCondition(tier1Section == null, "Table " + tableName + " has more than 1 section listed as Tier 1");
|
||||||
@ -658,13 +658,17 @@ public class QInstanceValidator
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private void validateFieldSection(QTableMetaData table, QFieldSection section, Set<String> fieldNamesInSections)
|
private void validateTableSection(QInstance qInstance, QTableMetaData table, QFieldSection section, Set<String> fieldNamesInSections)
|
||||||
{
|
{
|
||||||
assertCondition(StringUtils.hasContent(section.getName()), "Missing a name for field section in table " + table.getName() + ".");
|
assertCondition(StringUtils.hasContent(section.getName()), "Missing a name for field section in table " + table.getName() + ".");
|
||||||
assertCondition(StringUtils.hasContent(section.getLabel()), "Missing a label for field section in table " + table.getLabel() + ".");
|
assertCondition(StringUtils.hasContent(section.getLabel()), "Missing a label for field section in table " + table.getLabel() + ".");
|
||||||
if(assertCondition(CollectionUtils.nullSafeHasContents(section.getFieldNames()), "Table " + table.getName() + " section " + section.getName() + " does not have any fields."))
|
|
||||||
|
boolean hasFields = CollectionUtils.nullSafeHasContents(section.getFieldNames());
|
||||||
|
boolean hasWidget = StringUtils.hasContent(section.getWidgetName());
|
||||||
|
|
||||||
|
if(assertCondition(hasFields || hasWidget, "Table " + table.getName() + " section " + section.getName() + " does not have any fields or a widget."))
|
||||||
{
|
{
|
||||||
if(table.getFields() != null)
|
if(table.getFields() != null && hasFields)
|
||||||
{
|
{
|
||||||
for(String fieldName : section.getFieldNames())
|
for(String fieldName : section.getFieldNames())
|
||||||
{
|
{
|
||||||
@ -674,6 +678,10 @@ public class QInstanceValidator
|
|||||||
fieldNamesInSections.add(fieldName);
|
fieldNamesInSections.add(fieldName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(hasWidget)
|
||||||
|
{
|
||||||
|
assertCondition(qInstance.getWidget(section.getWidgetName()) != null, "Table " + table.getName() + " section " + section.getName() + " specifies widget " + section.getWidgetName() + ", which is not a widget in this instance.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Model containing data structure expected by frontend ChildRecordList widget
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class ChildRecordListData implements QWidget
|
||||||
|
{
|
||||||
|
private String title;
|
||||||
|
private QueryOutput queryOutput;
|
||||||
|
private QTableMetaData childTableMetaData;
|
||||||
|
|
||||||
|
private String tablePath;
|
||||||
|
private String viewAllLink;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ChildRecordListData(String title, QueryOutput queryOutput, QTableMetaData childTableMetaData, String tablePath, String viewAllLink)
|
||||||
|
{
|
||||||
|
this.title = title;
|
||||||
|
this.queryOutput = queryOutput;
|
||||||
|
this.childTableMetaData = childTableMetaData;
|
||||||
|
this.tablePath = tablePath;
|
||||||
|
this.viewAllLink = viewAllLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for type
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getType()
|
||||||
|
{
|
||||||
|
return WidgetType.CHILD_RECORD_LIST.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for title
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getTitle()
|
||||||
|
{
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for title
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setTitle(String title)
|
||||||
|
{
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for title
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ChildRecordListData withTitle(String title)
|
||||||
|
{
|
||||||
|
this.title = title;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for queryOutput
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QueryOutput getQueryOutput()
|
||||||
|
{
|
||||||
|
return queryOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for queryOutput
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setQueryOutput(QueryOutput queryOutput)
|
||||||
|
{
|
||||||
|
this.queryOutput = queryOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for queryOutput
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ChildRecordListData withQueryOutput(QueryOutput queryOutput)
|
||||||
|
{
|
||||||
|
this.queryOutput = queryOutput;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for childTableMetaData
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData getChildTableMetaData()
|
||||||
|
{
|
||||||
|
return childTableMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for childTableMetaData
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setChildTableMetaData(QTableMetaData childTableMetaData)
|
||||||
|
{
|
||||||
|
this.childTableMetaData = childTableMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for childTableMetaData
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public ChildRecordListData withChildTableMetaData(QTableMetaData childTableMetaData)
|
||||||
|
{
|
||||||
|
this.childTableMetaData = childTableMetaData;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for tablePath
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getTablePath()
|
||||||
|
{
|
||||||
|
return tablePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for tablePath
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setTablePath(String tablePath)
|
||||||
|
{
|
||||||
|
this.tablePath = tablePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for viewAllLink
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getViewAllLink()
|
||||||
|
{
|
||||||
|
return viewAllLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for viewAllLink
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setViewAllLink(String viewAllLink)
|
||||||
|
{
|
||||||
|
this.viewAllLink = viewAllLink;
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,8 @@ public enum WidgetType
|
|||||||
QUICK_SIGHT_CHART("quickSightChart"),
|
QUICK_SIGHT_CHART("quickSightChart"),
|
||||||
STATISTICS("statistics"),
|
STATISTICS("statistics"),
|
||||||
STEPPER("stepper"),
|
STEPPER("stepper"),
|
||||||
TABLE("table");
|
TABLE("table"),
|
||||||
|
CHILD_RECORD_LIST("childRecordList");
|
||||||
|
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
@ -28,10 +28,18 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction;
|
||||||
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.instances.QInstanceValidationKey;
|
import com.kingsrook.qqq.backend.core.instances.QInstanceValidationKey;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.automation.QAutomationProviderMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.automation.QAutomationProviderMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.branding.QBrandingMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.branding.QBrandingMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface;
|
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNodeType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
@ -64,6 +72,7 @@ public class QInstance
|
|||||||
// Important to use LinkedHashmap here, to preserve the order in which entries are added. //
|
// Important to use LinkedHashmap here, to preserve the order in which entries are added. //
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
private Map<String, QTableMetaData> tables = new LinkedHashMap<>();
|
private Map<String, QTableMetaData> tables = new LinkedHashMap<>();
|
||||||
|
private Map<String, QJoinMetaData> joins = new LinkedHashMap<>();
|
||||||
private Map<String, QPossibleValueSource> possibleValueSources = new LinkedHashMap<>();
|
private Map<String, QPossibleValueSource> possibleValueSources = new LinkedHashMap<>();
|
||||||
private Map<String, QProcessMetaData> processes = new LinkedHashMap<>();
|
private Map<String, QProcessMetaData> processes = new LinkedHashMap<>();
|
||||||
private Map<String, QAppMetaData> apps = new LinkedHashMap<>();
|
private Map<String, QAppMetaData> apps = new LinkedHashMap<>();
|
||||||
@ -79,6 +88,9 @@ public class QInstance
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private boolean hasBeenValidated = false;
|
private boolean hasBeenValidated = false;
|
||||||
|
|
||||||
|
private Map<String, String> memoizedTablePaths = new HashMap<>();
|
||||||
|
private Map<String, String> memoizedProcessPaths = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -118,6 +130,71 @@ public class QInstance
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Get the full path to a table
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getTablePath(AbstractActionInput actionInput, String tableName) throws QException
|
||||||
|
{
|
||||||
|
if(!memoizedTablePaths.containsKey(tableName))
|
||||||
|
{
|
||||||
|
MetaDataInput input = new MetaDataInput(this);
|
||||||
|
input.setSession(actionInput.getSession());
|
||||||
|
MetaDataOutput output = new MetaDataAction().execute(input);
|
||||||
|
memoizedTablePaths.put(tableName, searchAppTree(output.getAppTree(), tableName, AppTreeNodeType.TABLE, ""));
|
||||||
|
}
|
||||||
|
return (memoizedTablePaths.get(tableName));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Get the full path to a process
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getProcessPath(AbstractActionInput actionInput, String processName) throws QException
|
||||||
|
{
|
||||||
|
if(!memoizedProcessPaths.containsKey(processName))
|
||||||
|
{
|
||||||
|
MetaDataInput input = new MetaDataInput(this);
|
||||||
|
input.setSession(actionInput.getSession());
|
||||||
|
MetaDataOutput output = new MetaDataAction().execute(input);
|
||||||
|
return searchAppTree(output.getAppTree(), processName, AppTreeNodeType.PROCESS, "");
|
||||||
|
}
|
||||||
|
return (memoizedProcessPaths.get(processName));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private String searchAppTree(List<AppTreeNode> appTree, String tableName, AppTreeNodeType treeNodeType, String path)
|
||||||
|
{
|
||||||
|
if(appTree == null)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(AppTreeNode appTreeNode : appTree)
|
||||||
|
{
|
||||||
|
if(appTreeNode.getType().equals(treeNodeType) && appTreeNode.getName().equals(tableName))
|
||||||
|
{
|
||||||
|
return (path + "/" + tableName);
|
||||||
|
}
|
||||||
|
else if(appTreeNode.getType().equals(AppTreeNodeType.APP))
|
||||||
|
{
|
||||||
|
String subResult = searchAppTree(appTreeNode.getChildren(), tableName, treeNodeType, path + "/" + appTreeNode.getName());
|
||||||
|
if(subResult != null)
|
||||||
|
{
|
||||||
|
return (subResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -243,6 +320,71 @@ public class QInstance
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void addJoin(QJoinMetaData join)
|
||||||
|
{
|
||||||
|
addJoin(join.getName(), join);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void addJoin(String name, QJoinMetaData join)
|
||||||
|
{
|
||||||
|
if(!StringUtils.hasContent(name))
|
||||||
|
{
|
||||||
|
throw (new IllegalArgumentException("Attempted to add a join without a name."));
|
||||||
|
}
|
||||||
|
if(this.joins.containsKey(name))
|
||||||
|
{
|
||||||
|
throw (new IllegalArgumentException("Attempted to add a second join with name: " + name));
|
||||||
|
}
|
||||||
|
this.joins.put(name, join);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData getJoin(String name)
|
||||||
|
{
|
||||||
|
if(this.joins == null)
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.joins.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for joins
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Map<String, QJoinMetaData> getJoins()
|
||||||
|
{
|
||||||
|
return joins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for joins
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setJoins(Map<String, QJoinMetaData> joins)
|
||||||
|
{
|
||||||
|
this.joins = joins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -35,7 +35,6 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -92,11 +91,6 @@ public class QFrontendTableMetaData
|
|||||||
this.iconName = tableMetaData.getIcon().getName();
|
this.iconName = tableMetaData.getIcon().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CollectionUtils.nullSafeHasContents(tableMetaData.getWidgets()))
|
|
||||||
{
|
|
||||||
this.widgets = tableMetaData.getWidgets();
|
|
||||||
}
|
|
||||||
|
|
||||||
setCapabilities(backendForTable, tableMetaData);
|
setCapabilities(backendForTable, tableMetaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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.joins;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class JoinOn
|
||||||
|
{
|
||||||
|
private String leftField;
|
||||||
|
private String rightField;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public JoinOn()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Constructor
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public JoinOn(String leftField, String rightField)
|
||||||
|
{
|
||||||
|
this.leftField = leftField;
|
||||||
|
this.rightField = rightField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for leftField
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getLeftField()
|
||||||
|
{
|
||||||
|
return leftField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for leftField
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setLeftField(String leftField)
|
||||||
|
{
|
||||||
|
this.leftField = leftField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for leftField
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public JoinOn withLeftField(String leftField)
|
||||||
|
{
|
||||||
|
this.leftField = leftField;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for rightField
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getRightField()
|
||||||
|
{
|
||||||
|
return rightField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for rightField
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRightField(String rightField)
|
||||||
|
{
|
||||||
|
this.rightField = rightField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for rightField
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public JoinOn withRightField(String rightField)
|
||||||
|
{
|
||||||
|
this.rightField = rightField;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.joins;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Type for a QJoin.
|
||||||
|
**
|
||||||
|
** - One to One - what about zero??
|
||||||
|
** - One to Many - e.g., where the parent record really "owns" all of the child
|
||||||
|
** records. Like Order -> OrderLine.
|
||||||
|
** - Many to One - e.g., where a child references a parent, but we'd never really
|
||||||
|
** view or manage all of the children under the parent.
|
||||||
|
** - Many to Many - e.g., through an intersection table... ? Needs more thought.
|
||||||
|
*******************************************************************************/
|
||||||
|
public enum JoinType
|
||||||
|
{
|
||||||
|
ONE_TO_ONE,
|
||||||
|
ONE_TO_MANY,
|
||||||
|
MANY_TO_ONE,
|
||||||
|
MANY_TO_MANY
|
||||||
|
}
|
@ -0,0 +1,293 @@
|
|||||||
|
/*
|
||||||
|
* 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.joins;
|
||||||
|
|
||||||
|
|
||||||
|
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.utils.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public class QJoinMetaData
|
||||||
|
{
|
||||||
|
private String name;
|
||||||
|
private JoinType type;
|
||||||
|
private String leftTable;
|
||||||
|
private String rightTable;
|
||||||
|
|
||||||
|
private List<JoinOn> joinOns;
|
||||||
|
private List<QFilterOrderBy> orderBys;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for type
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public JoinType getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for type
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setType(JoinType type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for type
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withType(JoinType type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for leftTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getLeftTable()
|
||||||
|
{
|
||||||
|
return leftTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for leftTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setLeftTable(String leftTable)
|
||||||
|
{
|
||||||
|
this.leftTable = leftTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for leftTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withLeftTable(String leftTable)
|
||||||
|
{
|
||||||
|
this.leftTable = leftTable;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for rightTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getRightTable()
|
||||||
|
{
|
||||||
|
return rightTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for rightTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRightTable(String rightTable)
|
||||||
|
{
|
||||||
|
this.rightTable = rightTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for rightTable
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withRightTable(String rightTable)
|
||||||
|
{
|
||||||
|
this.rightTable = rightTable;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for joinOns
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<JoinOn> getJoinOns()
|
||||||
|
{
|
||||||
|
return joinOns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for joinOns
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setJoinOns(List<JoinOn> joinOns)
|
||||||
|
{
|
||||||
|
this.joinOns = joinOns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for joinOns
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withJoinOns(List<JoinOn> joinOns)
|
||||||
|
{
|
||||||
|
this.joinOns = joinOns;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for joinOns
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withJoinOn(JoinOn joinOn)
|
||||||
|
{
|
||||||
|
if(this.joinOns == null)
|
||||||
|
{
|
||||||
|
this.joinOns = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.joinOns.add(joinOn);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for orderBys
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QFilterOrderBy> getOrderBys()
|
||||||
|
{
|
||||||
|
return orderBys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for orderBys
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setOrderBys(List<QFilterOrderBy> orderBys)
|
||||||
|
{
|
||||||
|
this.orderBys = orderBys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for orderBys
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withOrderBys(List<QFilterOrderBy> orderBys)
|
||||||
|
{
|
||||||
|
this.orderBys = orderBys;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for orderBys
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withOrderBy(QFilterOrderBy orderBy)
|
||||||
|
{
|
||||||
|
if(this.orderBys == null)
|
||||||
|
{
|
||||||
|
this.orderBys = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.orderBys.add(orderBy);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QJoinMetaData withInferredName()
|
||||||
|
{
|
||||||
|
if(!StringUtils.hasContent(getLeftTable()) || !StringUtils.hasContent(getRightTable()))
|
||||||
|
{
|
||||||
|
throw (new IllegalStateException("Missing either a left or right table name when trying to set inferred name for join"));
|
||||||
|
}
|
||||||
|
return (withName(getLeftTable() + "Join" + getRightTable()));
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
|||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** A section of fields - a logical grouping.
|
** A section of fields - a logical grouping.
|
||||||
|
** TODO - this class should be named QTableSection!
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class QFieldSection
|
public class QFieldSection
|
||||||
{
|
{
|
||||||
@ -36,6 +37,7 @@ public class QFieldSection
|
|||||||
private Tier tier;
|
private Tier tier;
|
||||||
|
|
||||||
private List<String> fieldNames;
|
private List<String> fieldNames;
|
||||||
|
private String widgetName;
|
||||||
private QIcon icon;
|
private QIcon icon;
|
||||||
|
|
||||||
private boolean isHidden = false;
|
private boolean isHidden = false;
|
||||||
@ -78,6 +80,18 @@ public class QFieldSection
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection(String name, QIcon icon, Tier tier)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.icon = icon;
|
||||||
|
this.tier = tier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for name
|
** Getter for name
|
||||||
**
|
**
|
||||||
@ -280,4 +294,38 @@ public class QFieldSection
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for widgetName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getWidgetName()
|
||||||
|
{
|
||||||
|
return widgetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for widgetName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setWidgetName(String widgetName)
|
||||||
|
{
|
||||||
|
this.widgetName = widgetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for widgetName
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection withWidgetName(String widgetName)
|
||||||
|
{
|
||||||
|
this.widgetName = widgetName;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,6 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
|||||||
|
|
||||||
private List<QFieldSection> sections;
|
private List<QFieldSection> sections;
|
||||||
|
|
||||||
private List<String> widgets;
|
|
||||||
private List<AssociatedScript> associatedScripts;
|
private List<AssociatedScript> associatedScripts;
|
||||||
|
|
||||||
private Set<Capability> enabledCapabilities = new HashSet<>();
|
private Set<Capability> enabledCapabilities = new HashSet<>();
|
||||||
@ -726,40 +725,6 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Getter for widgets
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public List<String> getWidgets()
|
|
||||||
{
|
|
||||||
return widgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Setter for widgets
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public void setWidgets(List<String> widgets)
|
|
||||||
{
|
|
||||||
this.widgets = widgets;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Fluent setter for widgets
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public QTableMetaData withWidgets(List<String> widgets)
|
|
||||||
{
|
|
||||||
this.widgets = widgets;
|
|
||||||
return (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for associatedScripts
|
** Getter for associatedScripts
|
||||||
**
|
**
|
||||||
|
@ -128,6 +128,8 @@ public class MemoryRecordStore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BackendQueryFilterUtils.sortRecordList(input.getFilter(), records);
|
||||||
|
|
||||||
return (records);
|
return (records);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutp
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
@ -62,6 +63,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields;
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue;
|
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue;
|
||||||
@ -118,6 +122,8 @@ public class TestUtils
|
|||||||
|
|
||||||
public static final String TABLE_NAME_PERSON = "person";
|
public static final String TABLE_NAME_PERSON = "person";
|
||||||
public static final String TABLE_NAME_SHAPE = "shape";
|
public static final String TABLE_NAME_SHAPE = "shape";
|
||||||
|
public static final String TABLE_NAME_ORDER = "order";
|
||||||
|
public static final String TABLE_NAME_LINE_ITEM = "orderLine";
|
||||||
|
|
||||||
public static final String PROCESS_NAME_GREET_PEOPLE = "greet";
|
public static final String PROCESS_NAME_GREET_PEOPLE = "greet";
|
||||||
public static final String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
|
public static final String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
|
||||||
@ -161,6 +167,10 @@ public class TestUtils
|
|||||||
qInstance.addTable(defineTableIdAndNameOnly());
|
qInstance.addTable(defineTableIdAndNameOnly());
|
||||||
qInstance.addTable(defineTableShape());
|
qInstance.addTable(defineTableShape());
|
||||||
qInstance.addTable(defineTableBasepull());
|
qInstance.addTable(defineTableBasepull());
|
||||||
|
qInstance.addTable(defineTableOrder());
|
||||||
|
qInstance.addTable(defineTableLineItem());
|
||||||
|
|
||||||
|
qInstance.addJoin(defineJoinOrderLineItem());
|
||||||
|
|
||||||
qInstance.addPossibleValueSource(defineAutomationStatusPossibleValueSource());
|
qInstance.addPossibleValueSource(defineAutomationStatusPossibleValueSource());
|
||||||
qInstance.addPossibleValueSource(defineStatesPossibleValueSource());
|
qInstance.addPossibleValueSource(defineStatesPossibleValueSource());
|
||||||
@ -444,6 +454,60 @@ public class TestUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Define the order table used in standard tests.
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QTableMetaData defineTableOrder()
|
||||||
|
{
|
||||||
|
return new QTableMetaData()
|
||||||
|
.withName(TABLE_NAME_ORDER)
|
||||||
|
.withBackendName(MEMORY_BACKEND_NAME)
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("orderDate", QFieldType.DATE))
|
||||||
|
.withField(new QFieldMetaData("total", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Define the lineItem table used in standard tests.
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QTableMetaData defineTableLineItem()
|
||||||
|
{
|
||||||
|
return new QTableMetaData()
|
||||||
|
.withName(TABLE_NAME_LINE_ITEM)
|
||||||
|
.withBackendName(MEMORY_BACKEND_NAME)
|
||||||
|
.withPrimaryKeyField("id")
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("orderId", QFieldType.INTEGER))
|
||||||
|
.withField(new QFieldMetaData("lineNumber", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("sku", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("quantity", QFieldType.INTEGER));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QJoinMetaData defineJoinOrderLineItem()
|
||||||
|
{
|
||||||
|
return new QJoinMetaData()
|
||||||
|
.withName("orderLineItem")
|
||||||
|
.withType(JoinType.ONE_TO_MANY)
|
||||||
|
.withLeftTable(TABLE_NAME_ORDER)
|
||||||
|
.withRightTable(TABLE_NAME_LINE_ITEM)
|
||||||
|
.withJoinOn(new JoinOn("id", "orderId"))
|
||||||
|
.withOrderBy(new QFilterOrderBy("lineNumber"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
Reference in New Issue
Block a user