mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Feedback from code reviews
This commit is contained in:
@ -30,13 +30,10 @@ import com.kingsrook.qqq.backend.core.modules.authentication.QAuthenticationModu
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Utility methods to be shared by all of the various Actions (e.g., InsertAction)
|
||||
*******************************************************************************/
|
||||
public class ActionHelper
|
||||
{
|
||||
private int f;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
@ -22,7 +22,6 @@
|
||||
package com.kingsrook.qqq.backend.core.actions;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
|
||||
|
||||
@ -31,12 +30,14 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
** part of a transaction.
|
||||
**
|
||||
** Most obvious use-case would be a JDBC Connection. See subclass in rdbms module.
|
||||
**
|
||||
** Note: One would imagine that this class shouldn't ever implement Serializable...
|
||||
*******************************************************************************/
|
||||
public class QBackendTransaction
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Commit the transaction.
|
||||
*******************************************************************************/
|
||||
public void commit() throws QException
|
||||
{
|
||||
@ -48,7 +49,7 @@ public class QBackendTransaction
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Rollback the transaction.
|
||||
*******************************************************************************/
|
||||
public void rollback() throws QException
|
||||
{
|
||||
@ -60,18 +61,8 @@ public class QBackendTransaction
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Closes this stream and releases any system resources associated
|
||||
* with it. If the stream is already closed then invoking this
|
||||
* method has no effect.
|
||||
*
|
||||
* <p> As noted in {@link AutoCloseable#close()}, cases where the
|
||||
* close may fail require careful attention. It is strongly advised
|
||||
* to relinquish the underlying resources and to internally
|
||||
* <em>mark</em> the {@code Closeable} as closed, prior to throwing
|
||||
* the {@code IOException}.
|
||||
*
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
** Close any resources associated with the transaction. In theory, should only
|
||||
** be called after a commit or rollback was done.
|
||||
*******************************************************************************/
|
||||
public void close()
|
||||
{
|
||||
|
@ -30,6 +30,7 @@ import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
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.frontend.AppTreeNode;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
@ -55,7 +56,7 @@ public class MetaDataAction
|
||||
// todo pre-customization - just get to modify the request?
|
||||
MetaDataOutput metaDataOutput = new MetaDataOutput();
|
||||
|
||||
Map<String, QFrontendAppMetaData> treeNodes = new LinkedHashMap<>();
|
||||
Map<String, AppTreeNode> treeNodes = new LinkedHashMap<>();
|
||||
|
||||
/////////////////////////////////////
|
||||
// map tables to frontend metadata //
|
||||
@ -64,7 +65,7 @@ public class MetaDataAction
|
||||
for(Map.Entry<String, QTableMetaData> entry : metaDataInput.getInstance().getTables().entrySet())
|
||||
{
|
||||
tables.put(entry.getKey(), new QFrontendTableMetaData(entry.getValue(), false));
|
||||
treeNodes.put(entry.getKey(), new QFrontendAppMetaData(entry.getValue()));
|
||||
treeNodes.put(entry.getKey(), new AppTreeNode(entry.getValue()));
|
||||
}
|
||||
metaDataOutput.setTables(tables);
|
||||
|
||||
@ -75,7 +76,7 @@ public class MetaDataAction
|
||||
for(Map.Entry<String, QProcessMetaData> entry : metaDataInput.getInstance().getProcesses().entrySet())
|
||||
{
|
||||
processes.put(entry.getKey(), new QFrontendProcessMetaData(entry.getValue(), false));
|
||||
treeNodes.put(entry.getKey(), new QFrontendAppMetaData(entry.getValue()));
|
||||
treeNodes.put(entry.getKey(), new AppTreeNode(entry.getValue()));
|
||||
}
|
||||
metaDataOutput.setProcesses(processes);
|
||||
|
||||
@ -86,11 +87,11 @@ public class MetaDataAction
|
||||
for(Map.Entry<String, QAppMetaData> entry : metaDataInput.getInstance().getApps().entrySet())
|
||||
{
|
||||
apps.put(entry.getKey(), new QFrontendAppMetaData(entry.getValue()));
|
||||
treeNodes.put(entry.getKey(), new QFrontendAppMetaData(entry.getValue()));
|
||||
treeNodes.put(entry.getKey(), new AppTreeNode(entry.getValue()));
|
||||
|
||||
for(QAppChildMetaData child : entry.getValue().getChildren())
|
||||
{
|
||||
apps.get(entry.getKey()).addChild(new QFrontendAppMetaData(child));
|
||||
apps.get(entry.getKey()).addChild(new AppTreeNode(child));
|
||||
}
|
||||
}
|
||||
metaDataOutput.setApps(apps);
|
||||
@ -98,7 +99,7 @@ public class MetaDataAction
|
||||
////////////////////////////////////////////////
|
||||
// organize app tree nodes by their hierarchy //
|
||||
////////////////////////////////////////////////
|
||||
List<QFrontendAppMetaData> appTree = new ArrayList<>();
|
||||
List<AppTreeNode> appTree = new ArrayList<>();
|
||||
for(QAppMetaData appMetaData : metaDataInput.getInstance().getApps().values())
|
||||
{
|
||||
if(appMetaData.getParentAppName() == null)
|
||||
@ -118,9 +119,9 @@ public class MetaDataAction
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void buildAppTree(Map<String, QFrontendAppMetaData> treeNodes, List<QFrontendAppMetaData> nodeList, QAppChildMetaData childMetaData)
|
||||
private void buildAppTree(Map<String, AppTreeNode> treeNodes, List<AppTreeNode> nodeList, QAppChildMetaData childMetaData)
|
||||
{
|
||||
QFrontendAppMetaData treeNode = treeNodes.get(childMetaData.getName());
|
||||
AppTreeNode treeNode = treeNodes.get(childMetaData.getName());
|
||||
if(treeNode == null)
|
||||
{
|
||||
return;
|
||||
|
@ -50,7 +50,10 @@ public class QueryAction
|
||||
QueryOutput queryOutput = qModule.getQueryInterface().execute(queryInput);
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
|
||||
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), queryOutput.getRecords());
|
||||
if (queryInput.getRecordPipe() == null)
|
||||
{
|
||||
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), queryOutput.getRecords());
|
||||
}
|
||||
|
||||
return queryOutput;
|
||||
}
|
||||
|
@ -447,7 +447,6 @@ public class QInstanceEnricher
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
<<<<<<< HEAD
|
||||
** for all fields in a table, set their backendName, using the default "inference" logic
|
||||
** see {@link #inferBackendName(String)}
|
||||
*******************************************************************************/
|
||||
@ -482,6 +481,17 @@ public class QInstanceEnricher
|
||||
/*******************************************************************************
|
||||
** Do a default mapping from a camelCase field name to an underscore_style
|
||||
** name for a backend.
|
||||
**
|
||||
** Examples:
|
||||
** <ul>
|
||||
** <li>wordAnotherWordMoreWords -> word_another_word_more_words</li>
|
||||
** <li>lUlUlUl -> l_ul_ul_ul</li>
|
||||
** <li>StartsUpper -> starts_upper</li>
|
||||
** <li>TLAFirst -> tla_first</li>
|
||||
** <li>wordThenTLAInMiddle -> word_then_tla_in_middle</li>
|
||||
** <li>endWithTLA -> end_with_tla</li>
|
||||
** <li>TLAAndAnotherTLA -> tla_and_another_tla</li>
|
||||
** </ul>
|
||||
*******************************************************************************/
|
||||
static String inferBackendName(String fieldName)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.model.actions.metadata;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
||||
@ -40,7 +41,7 @@ public class MetaDataOutput extends AbstractActionOutput
|
||||
private Map<String, QFrontendProcessMetaData> processes;
|
||||
private Map<String, QFrontendAppMetaData> apps;
|
||||
|
||||
private List<QFrontendAppMetaData> appTree;
|
||||
private List<AppTreeNode> appTree;
|
||||
|
||||
|
||||
|
||||
@ -93,7 +94,7 @@ public class MetaDataOutput extends AbstractActionOutput
|
||||
** Getter for appTree
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QFrontendAppMetaData> getAppTree()
|
||||
public List<AppTreeNode> getAppTree()
|
||||
{
|
||||
return appTree;
|
||||
}
|
||||
@ -104,7 +105,7 @@ public class MetaDataOutput extends AbstractActionOutput
|
||||
** Setter for appTree
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setAppTree(List<QFrontendAppMetaData> appTree)
|
||||
public void setAppTree(List<AppTreeNode> appTree)
|
||||
{
|
||||
this.appTree = appTree;
|
||||
}
|
||||
|
@ -26,17 +26,22 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Annotation to place onto fields in a QRecordEntity, to add additional attributes
|
||||
** for propagating down into the corresponding QFieldMetaData
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface QField
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
String label() default "";
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -51,4 +56,13 @@ public @interface QField
|
||||
**
|
||||
*******************************************************************************/
|
||||
boolean isEditable() default true;
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
String displayFormat() default "";
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// new attributes here likely need implementation in QFieldMetaData.constructFromGetter //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import java.util.Optional;
|
||||
import com.github.hervian.reflection.Fun;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
@ -120,10 +119,20 @@ public class QFieldMetaData
|
||||
setIsRequired(fieldAnnotation.isRequired());
|
||||
setIsEditable(fieldAnnotation.isEditable());
|
||||
|
||||
if(StringUtils.hasContent(fieldAnnotation.label()))
|
||||
{
|
||||
setLabel(fieldAnnotation.label());
|
||||
}
|
||||
|
||||
if(StringUtils.hasContent(fieldAnnotation.backendName()))
|
||||
{
|
||||
setBackendName(fieldAnnotation.backendName());
|
||||
}
|
||||
|
||||
if(StringUtils.hasContent(fieldAnnotation.displayFormat()))
|
||||
{
|
||||
setDisplayFormat(fieldAnnotation.displayFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(QException qe)
|
||||
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.frontend;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Frontend-version of objects that are parts of the app-hierarchy/tree.
|
||||
** e.g., Tables, Processes, and Apps themselves (since they can be nested).
|
||||
**
|
||||
** These objects are organized into a tree - where each Node can have 0 or more
|
||||
** other Nodes as children.
|
||||
*******************************************************************************/
|
||||
public class AppTreeNode
|
||||
{
|
||||
private AppTreeNodeType type;
|
||||
private String name;
|
||||
private String label;
|
||||
private List<AppTreeNode> children;
|
||||
|
||||
private String iconName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppTreeNode(QAppChildMetaData appChildMetaData)
|
||||
{
|
||||
this.name = appChildMetaData.getName();
|
||||
this.label = appChildMetaData.getLabel();
|
||||
|
||||
if(appChildMetaData.getClass().equals(QTableMetaData.class))
|
||||
{
|
||||
this.type = AppTreeNodeType.TABLE;
|
||||
}
|
||||
else if(appChildMetaData.getClass().equals(QProcessMetaData.class))
|
||||
{
|
||||
this.type = AppTreeNodeType.PROCESS;
|
||||
}
|
||||
else if(appChildMetaData.getClass().equals(QAppMetaData.class))
|
||||
{
|
||||
this.type = AppTreeNodeType.APP;
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new IllegalStateException("Unrecognized class for app child meta data: " + appChildMetaData.getClass()));
|
||||
}
|
||||
|
||||
if(appChildMetaData.getIcon() != null)
|
||||
{
|
||||
// todo - propagate icons from parents, if they aren't set here...
|
||||
this.iconName = appChildMetaData.getIcon().getName();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppTreeNodeType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for children
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<AppTreeNode> getChildren()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for iconName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getIconName()
|
||||
{
|
||||
return iconName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addChild(AppTreeNode childTreeNode)
|
||||
{
|
||||
if(children == null)
|
||||
{
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
children.add(childTreeNode);
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.frontend;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Type for an Node in the an app tree.
|
||||
*******************************************************************************/
|
||||
public enum AppTreeNodeType
|
||||
{
|
||||
|
@ -27,10 +27,6 @@ import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -40,12 +36,10 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class QFrontendAppMetaData
|
||||
{
|
||||
private AppTreeNodeType type;
|
||||
|
||||
private String name;
|
||||
private String label;
|
||||
|
||||
private List<QFrontendAppMetaData> children = new ArrayList<>();
|
||||
private List<AppTreeNode> children = new ArrayList<>();
|
||||
|
||||
private String iconName;
|
||||
|
||||
@ -59,24 +53,7 @@ public class QFrontendAppMetaData
|
||||
this.name = appChildMetaData.getName();
|
||||
this.label = appChildMetaData.getLabel();
|
||||
|
||||
if(appChildMetaData.getClass().equals(QTableMetaData.class))
|
||||
{
|
||||
this.type = AppTreeNodeType.TABLE;
|
||||
}
|
||||
else if(appChildMetaData.getClass().equals(QProcessMetaData.class))
|
||||
{
|
||||
this.type = AppTreeNodeType.PROCESS;
|
||||
}
|
||||
else if(appChildMetaData.getClass().equals(QAppMetaData.class))
|
||||
{
|
||||
this.type = AppTreeNodeType.APP;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new IllegalStateException("Unrecognized class for app child meta data: " + appChildMetaData.getClass()));
|
||||
}
|
||||
|
||||
if(appChildMetaData.getIcon() != null && StringUtils.hasContent(appChildMetaData.getIcon().getName()))
|
||||
if(appChildMetaData.getIcon() != null)
|
||||
{
|
||||
this.iconName = appChildMetaData.getIcon().getName();
|
||||
}
|
||||
@ -106,22 +83,11 @@ public class QFrontendAppMetaData
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AppTreeNodeType getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for children
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QFrontendAppMetaData> getChildren()
|
||||
public List<AppTreeNode> getChildren()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
@ -153,12 +119,12 @@ public class QFrontendAppMetaData
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addChild(QFrontendAppMetaData qFrontendAppMetaData)
|
||||
public void addChild(AppTreeNode childAppTreeNode)
|
||||
{
|
||||
if(children == null)
|
||||
{
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
children.add(qFrontendAppMetaData);
|
||||
children.add(childAppTreeNode);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -81,7 +80,7 @@ public class QFrontendProcessMetaData
|
||||
}
|
||||
}
|
||||
|
||||
if(processMetaData.getIcon() != null && StringUtils.hasContent(processMetaData.getIcon().getName()))
|
||||
if(processMetaData.getIcon() != null)
|
||||
{
|
||||
this.iconName = processMetaData.getIcon().getName();
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
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.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -78,7 +77,7 @@ public class QFrontendTableMetaData
|
||||
this.sections = tableMetaData.getSections();
|
||||
}
|
||||
|
||||
if(tableMetaData.getIcon() != null && StringUtils.hasContent(tableMetaData.getIcon().getName()))
|
||||
if(tableMetaData.getIcon() != null)
|
||||
{
|
||||
this.iconName = tableMetaData.getIcon().getName();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.layout;
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface shared by meta-data objects which can be placed into an App.
|
||||
** e.g., Tables, Processes, and Apps themselves (since they can be nested)
|
||||
*******************************************************************************/
|
||||
public interface QAppChildMetaData
|
||||
{
|
||||
|
@ -27,7 +27,8 @@ import java.util.List;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** MetaData definition of an App - an entity that organizes tables & processes
|
||||
** and can be arranged hierarchically (e.g, apps can contain other apps).
|
||||
*******************************************************************************/
|
||||
public class QAppMetaData implements QAppChildMetaData
|
||||
{
|
||||
|
@ -30,7 +30,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntityField;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
@ -467,17 +466,6 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QTableMetaData withInferredFieldBackendNames()
|
||||
{
|
||||
QInstanceEnricher.setInferredFieldBackendNames(this);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for parentAppName
|
||||
**
|
||||
|
@ -46,7 +46,7 @@ public class BasicETLLoadFunction implements BackendStep
|
||||
private static final Logger LOG = LogManager.getLogger(BasicETLLoadFunction.class);
|
||||
|
||||
private QBackendTransaction transaction;
|
||||
private boolean returnStoredRecords = false;
|
||||
private boolean returnStoredRecords = true;
|
||||
|
||||
|
||||
|
||||
|
@ -78,12 +78,12 @@ public class StreamedETLBackendStep implements BackendStep
|
||||
// run the query action as an async job //
|
||||
//////////////////////////////////////////
|
||||
AsyncJobManager asyncJobManager = new AsyncJobManager();
|
||||
String queryJobUUID = asyncJobManager.startJob("ReportAction>QueryAction", (status) ->
|
||||
String queryJobUUID = asyncJobManager.startJob("StreamedETL>QueryAction", (status) ->
|
||||
{
|
||||
basicETLExtractFunction.run(runBackendStepInput, runBackendStepOutput);
|
||||
return (runBackendStepOutput);
|
||||
});
|
||||
LOG.info("Started query job [" + queryJobUUID + "] for report");
|
||||
LOG.info("Started query job [" + queryJobUUID + "] for streamed ETL");
|
||||
|
||||
AsyncJobState queryJobState = AsyncJobState.RUNNING;
|
||||
AsyncJobStatus asyncJobStatus = null;
|
||||
@ -141,6 +141,14 @@ public class StreamedETLBackendStep implements BackendStep
|
||||
|
||||
LOG.info("Query job [" + queryJobUUID + "] for ETL completed with status: " + asyncJobStatus);
|
||||
|
||||
/////////////////////////////////////////
|
||||
// propagate errors from the query job //
|
||||
/////////////////////////////////////////
|
||||
if(asyncJobStatus.getState().equals(AsyncJobState.ERROR))
|
||||
{
|
||||
throw (new QException("Query job failed with an error", asyncJobStatus.getCaughtException()));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// send the final records to transform & load steps //
|
||||
//////////////////////////////////////////////////////
|
||||
@ -207,6 +215,7 @@ public class StreamedETLBackendStep implements BackendStep
|
||||
|
||||
runBackendStepInput.setRecords(runBackendStepOutput.getRecords());
|
||||
BasicETLLoadFunction basicETLLoadFunction = new BasicETLLoadFunction();
|
||||
basicETLLoadFunction.setReturnStoredRecords(false);
|
||||
basicETLLoadFunction.setTransaction(transaction);
|
||||
basicETLLoadFunction.run(runBackendStepInput, runBackendStepOutput);
|
||||
|
||||
|
@ -42,8 +42,8 @@ import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||
*******************************************************************************/
|
||||
public class ValueUtils
|
||||
{
|
||||
private static final DateTimeFormatter yyyyMMddWithDashesFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
private static final DateTimeFormatter MdyyyyWithSlashesFormatter = DateTimeFormatter.ofPattern("M/d/yyyy");
|
||||
private static final DateTimeFormatter dateTimeFormatter_yyyyMMddWithDashes = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
private static final DateTimeFormatter dateTimeFormatter_MdyyyyWithSlashes = DateTimeFormatter.ofPattern("M/d/yyyy");
|
||||
|
||||
|
||||
|
||||
@ -262,7 +262,7 @@ public class ValueUtils
|
||||
private static LocalDate tryLocalDateParsers(String s)
|
||||
{
|
||||
DateTimeParseException lastException = null;
|
||||
for(DateTimeFormatter dateTimeFormatter : List.of(yyyyMMddWithDashesFormatter, MdyyyyWithSlashesFormatter))
|
||||
for(DateTimeFormatter dateTimeFormatter : List.of(dateTimeFormatter_yyyyMMddWithDashes, dateTimeFormatter_MdyyyyWithSlashes))
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -386,7 +386,6 @@ public class ValueUtils
|
||||
}
|
||||
else if(value instanceof Calendar c)
|
||||
{
|
||||
TimeZone tz = c.getTimeZone();
|
||||
return (c.toInstant());
|
||||
}
|
||||
else if(value instanceof LocalDateTime ldt)
|
||||
|
@ -30,6 +30,7 @@ import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
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.frontend.AppTreeNode;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -84,7 +85,7 @@ class MetaDataActionTest
|
||||
|
||||
QFrontendAppMetaData peopleApp = apps.get(TestUtils.APP_NAME_PEOPLE);
|
||||
assertThat(peopleApp.getChildren()).isNotEmpty();
|
||||
Optional<QFrontendAppMetaData> greetingsAppUnderPeopleFromMapOptional = peopleApp.getChildren().stream()
|
||||
Optional<AppTreeNode> greetingsAppUnderPeopleFromMapOptional = peopleApp.getChildren().stream()
|
||||
.filter(e -> e.getName().equals(TestUtils.APP_NAME_GREETINGS)).findFirst();
|
||||
assertThat(greetingsAppUnderPeopleFromMapOptional).isPresent();
|
||||
|
||||
@ -97,18 +98,18 @@ class MetaDataActionTest
|
||||
///////////////////////////////////////////////
|
||||
// assert against the hierarchical apps tree //
|
||||
///////////////////////////////////////////////
|
||||
List<QFrontendAppMetaData> appTree = result.getAppTree();
|
||||
Set<String> appNamesInTopOfTree = appTree.stream().map(QFrontendAppMetaData::getName).collect(Collectors.toSet());
|
||||
List<AppTreeNode> appTree = result.getAppTree();
|
||||
Set<String> appNamesInTopOfTree = appTree.stream().map(AppTreeNode::getName).collect(Collectors.toSet());
|
||||
assertThat(appNamesInTopOfTree).contains(TestUtils.APP_NAME_PEOPLE);
|
||||
assertThat(appNamesInTopOfTree).contains(TestUtils.APP_NAME_MISCELLANEOUS);
|
||||
assertThat(appNamesInTopOfTree).doesNotContain(TestUtils.APP_NAME_GREETINGS);
|
||||
|
||||
Optional<QFrontendAppMetaData> peopleAppOptional = appTree.stream()
|
||||
Optional<AppTreeNode> peopleAppOptional = appTree.stream()
|
||||
.filter(e -> e.getName().equals(TestUtils.APP_NAME_PEOPLE)).findFirst();
|
||||
assertThat(peopleAppOptional).isPresent();
|
||||
assertThat(peopleAppOptional.get().getChildren()).isNotEmpty();
|
||||
|
||||
Optional<QFrontendAppMetaData> greetingsAppUnderPeopleFromTree = peopleAppOptional.get().getChildren().stream()
|
||||
Optional<AppTreeNode> greetingsAppUnderPeopleFromTree = peopleAppOptional.get().getChildren().stream()
|
||||
.filter(e -> e.getName().equals(TestUtils.APP_NAME_GREETINGS)).findFirst();
|
||||
assertThat(greetingsAppUnderPeopleFromTree).isPresent();
|
||||
|
||||
|
@ -26,6 +26,7 @@ import java.math.BigDecimal;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.testentities.Item;
|
||||
import com.kingsrook.qqq.backend.core.model.data.testentities.ItemWithPrimitives;
|
||||
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.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
@ -177,6 +178,8 @@ class QRecordEntityTest
|
||||
///////////////////////////////////////////////////////////////
|
||||
// assert about attributes that came from @QField annotation //
|
||||
///////////////////////////////////////////////////////////////
|
||||
assertEquals("SKU", qTableMetaData.getField("sku").getLabel());
|
||||
assertEquals(DisplayFormat.COMMAS, qTableMetaData.getField("quantity").getDisplayFormat());
|
||||
assertTrue(qTableMetaData.getField("sku").getIsRequired());
|
||||
assertFalse(qTableMetaData.getField("quantity").getIsEditable());
|
||||
assertEquals("is_featured", qTableMetaData.getField("featured").getBackendName());
|
||||
|
@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.model.data.testentities;
|
||||
import java.math.BigDecimal;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -32,13 +33,13 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
*******************************************************************************/
|
||||
public class Item extends QRecordEntity
|
||||
{
|
||||
@QField(isRequired = true)
|
||||
@QField(isRequired = true, label = "SKU")
|
||||
private String sku;
|
||||
|
||||
@QField()
|
||||
private String description;
|
||||
|
||||
@QField(isEditable = false)
|
||||
@QField(isEditable = false, displayFormat = DisplayFormat.COMMAS)
|
||||
private Integer quantity;
|
||||
|
||||
private BigDecimal price;
|
||||
|
@ -60,21 +60,8 @@ public class Auth0AuthenticationModuleTest
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test an expired token where 'now' is set to a time that would not require it to be
|
||||
** re-checked, so it'll show as valid
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
public void testLastTimeCheckedNow()
|
||||
{
|
||||
assertTrue(testLastTimeChecked(Instant.now(), UNDECODABLE_TOKEN), "A session just checked 'now' should always be valid");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test an expired token where 'now' is set to a time that would not require it to be
|
||||
** re-checked, so it'll show as valid
|
||||
** Test a token where last-checked is set to a time that would not require it to be
|
||||
** re-checked, so it'll show as valid no matter what the token is.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
@ -87,8 +74,8 @@ public class Auth0AuthenticationModuleTest
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test an expired token where 'now' is set to a time that would require it to be
|
||||
** re-checked
|
||||
** Test a token where last-checked is set to a time that would require it to be
|
||||
** re-checked, so it'll show as invalid.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
@ -101,8 +88,8 @@ public class Auth0AuthenticationModuleTest
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test an expired token where 'now' is set to a time that would require it to be
|
||||
** re-checked
|
||||
** Test a token where last-checked is past the threshold, so it'll get re-checked,
|
||||
** and will fail.
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
|
@ -55,7 +55,10 @@ class StreamedETLProcessTest
|
||||
|
||||
RunProcessOutput result = new RunProcessAction().execute(request);
|
||||
assertNotNull(result);
|
||||
assertTrue(result.getRecords().stream().allMatch(r -> r.getValues().containsKey("id")), "records should have an id, set by the process");
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// since this is streamed, assert there are no records in the output //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
assertTrue(result.getRecords().isEmpty());
|
||||
assertTrue(result.getException().isEmpty());
|
||||
}
|
||||
|
||||
@ -77,12 +80,14 @@ class StreamedETLProcessTest
|
||||
// define our mapping from destination-table field names to source-table field names //
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
QKeyBasedFieldMapping mapping = new QKeyBasedFieldMapping().withMapping("name", "firstName");
|
||||
// request.addValue(StreamedETLProcess.FIELD_MAPPING_JSON, JsonUtils.toJson(mapping.getMapping()));
|
||||
request.addValue(StreamedETLProcess.FIELD_MAPPING_JSON, JsonUtils.toJson(mapping));
|
||||
|
||||
RunProcessOutput result = new RunProcessAction().execute(request);
|
||||
assertNotNull(result);
|
||||
assertTrue(result.getRecords().stream().allMatch(r -> r.getValues().containsKey("id")), "records should have an id, set by the process");
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// since this is streamed, assert there are no records in the output //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
assertTrue(result.getRecords().isEmpty());
|
||||
assertTrue(result.getException().isEmpty());
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,6 @@ class ValueUtilsTest
|
||||
@Test
|
||||
void testGetValueAsString() throws QValueException
|
||||
{
|
||||
//noinspection ConstantConditions
|
||||
assertNull(ValueUtils.getValueAsString(null));
|
||||
assertEquals("", ValueUtils.getValueAsString(""));
|
||||
assertEquals(" ", ValueUtils.getValueAsString(" "));
|
||||
@ -164,26 +163,28 @@ class ValueUtilsTest
|
||||
@Test
|
||||
void testGetValueAsLocalDate() throws QValueException
|
||||
{
|
||||
LocalDate expected = LocalDate.of(1980, Month.MAY, 31);
|
||||
|
||||
assertNull(ValueUtils.getValueAsLocalDate(null));
|
||||
assertNull(ValueUtils.getValueAsLocalDate(""));
|
||||
assertNull(ValueUtils.getValueAsLocalDate(" "));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDate.of(1980, 5, 31)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.sql.Date(80, 4, 31)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(LocalDate.of(1980, 5, 31)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new java.sql.Date(80, 4, 31)));
|
||||
//noinspection MagicConstant
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, 4, 31)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 12, 0)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 4, 0)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 22, 0)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new java.util.Date(80, 4, 31)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 12, 0)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 4, 0)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new java.util.Date(80, Calendar.MAY, 31, 22, 0)));
|
||||
//noinspection MagicConstant
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, 4, 31)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, Calendar.MAY, 31)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 12, 0)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 4, 0)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 22, 0)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, Month.MAY, 31, 12, 0)));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate("1980-05-31"));
|
||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate("05/31/1980"));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, 4, 31)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, Calendar.MAY, 31)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 12, 0)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 4, 0)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, 5, 31, 22, 0)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, Month.MAY, 31, 12, 0)));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate("1980-05-31"));
|
||||
assertEquals(expected, ValueUtils.getValueAsLocalDate("05/31/1980"));
|
||||
|
||||
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a"));
|
||||
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a,b"));
|
||||
|
Reference in New Issue
Block a user