Feedback from code reviews

This commit is contained in:
2022-08-11 09:42:30 -05:00
parent 9a7acce3c6
commit 3b1f0b47c1
34 changed files with 486 additions and 196 deletions

View File

@ -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;
/*******************************************************************************
**

View File

@ -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()
{

View File

@ -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;

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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 //
//////////////////////////////////////////////////////////////////////////////////////////
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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
{

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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
{

View File

@ -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
{

View File

@ -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
**

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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();

View File

@ -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());

View File

@ -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;

View File

@ -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

View File

@ -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());
}

View File

@ -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"));