mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +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
|
public class ActionHelper
|
||||||
{
|
{
|
||||||
private int f;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
package com.kingsrook.qqq.backend.core.actions;
|
package com.kingsrook.qqq.backend.core.actions;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
|
|
||||||
|
|
||||||
@ -31,12 +30,14 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
|||||||
** part of a transaction.
|
** part of a transaction.
|
||||||
**
|
**
|
||||||
** Most obvious use-case would be a JDBC Connection. See subclass in rdbms module.
|
** 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
|
public class QBackendTransaction
|
||||||
{
|
{
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
** Commit the transaction.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void commit() throws QException
|
public void commit() throws QException
|
||||||
{
|
{
|
||||||
@ -48,7 +49,7 @@ public class QBackendTransaction
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
** Rollback the transaction.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void rollback() throws QException
|
public void rollback() throws QException
|
||||||
{
|
{
|
||||||
@ -60,18 +61,8 @@ public class QBackendTransaction
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Closes this stream and releases any system resources associated
|
** Close any resources associated with the transaction. In theory, should only
|
||||||
* with it. If the stream is already closed then invoking this
|
** be called after a commit or rollback was done.
|
||||||
* 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
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void close()
|
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.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
|
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.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.QFrontendAppMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
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?
|
// todo pre-customization - just get to modify the request?
|
||||||
MetaDataOutput metaDataOutput = new MetaDataOutput();
|
MetaDataOutput metaDataOutput = new MetaDataOutput();
|
||||||
|
|
||||||
Map<String, QFrontendAppMetaData> treeNodes = new LinkedHashMap<>();
|
Map<String, AppTreeNode> treeNodes = new LinkedHashMap<>();
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
// map tables to frontend metadata //
|
// map tables to frontend metadata //
|
||||||
@ -64,7 +65,7 @@ public class MetaDataAction
|
|||||||
for(Map.Entry<String, QTableMetaData> entry : metaDataInput.getInstance().getTables().entrySet())
|
for(Map.Entry<String, QTableMetaData> entry : metaDataInput.getInstance().getTables().entrySet())
|
||||||
{
|
{
|
||||||
tables.put(entry.getKey(), new QFrontendTableMetaData(entry.getValue(), false));
|
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);
|
metaDataOutput.setTables(tables);
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ public class MetaDataAction
|
|||||||
for(Map.Entry<String, QProcessMetaData> entry : metaDataInput.getInstance().getProcesses().entrySet())
|
for(Map.Entry<String, QProcessMetaData> entry : metaDataInput.getInstance().getProcesses().entrySet())
|
||||||
{
|
{
|
||||||
processes.put(entry.getKey(), new QFrontendProcessMetaData(entry.getValue(), false));
|
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);
|
metaDataOutput.setProcesses(processes);
|
||||||
|
|
||||||
@ -86,11 +87,11 @@ public class MetaDataAction
|
|||||||
for(Map.Entry<String, QAppMetaData> entry : metaDataInput.getInstance().getApps().entrySet())
|
for(Map.Entry<String, QAppMetaData> entry : metaDataInput.getInstance().getApps().entrySet())
|
||||||
{
|
{
|
||||||
apps.put(entry.getKey(), new QFrontendAppMetaData(entry.getValue()));
|
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())
|
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);
|
metaDataOutput.setApps(apps);
|
||||||
@ -98,7 +99,7 @@ public class MetaDataAction
|
|||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
// organize app tree nodes by their hierarchy //
|
// organize app tree nodes by their hierarchy //
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
List<QFrontendAppMetaData> appTree = new ArrayList<>();
|
List<AppTreeNode> appTree = new ArrayList<>();
|
||||||
for(QAppMetaData appMetaData : metaDataInput.getInstance().getApps().values())
|
for(QAppMetaData appMetaData : metaDataInput.getInstance().getApps().values())
|
||||||
{
|
{
|
||||||
if(appMetaData.getParentAppName() == null)
|
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)
|
if(treeNode == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -50,7 +50,10 @@ public class QueryAction
|
|||||||
QueryOutput queryOutput = qModule.getQueryInterface().execute(queryInput);
|
QueryOutput queryOutput = qModule.getQueryInterface().execute(queryInput);
|
||||||
// todo post-customization - can do whatever w/ the result if you want
|
// todo post-customization - can do whatever w/ the result if you want
|
||||||
|
|
||||||
|
if (queryInput.getRecordPipe() == null)
|
||||||
|
{
|
||||||
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), queryOutput.getRecords());
|
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), queryOutput.getRecords());
|
||||||
|
}
|
||||||
|
|
||||||
return queryOutput;
|
return queryOutput;
|
||||||
}
|
}
|
||||||
|
@ -447,7 +447,6 @@ public class QInstanceEnricher
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
<<<<<<< HEAD
|
|
||||||
** for all fields in a table, set their backendName, using the default "inference" logic
|
** for all fields in a table, set their backendName, using the default "inference" logic
|
||||||
** see {@link #inferBackendName(String)}
|
** see {@link #inferBackendName(String)}
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -482,6 +481,17 @@ public class QInstanceEnricher
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Do a default mapping from a camelCase field name to an underscore_style
|
** Do a default mapping from a camelCase field name to an underscore_style
|
||||||
** name for a backend.
|
** 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)
|
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
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.QFrontendAppMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData;
|
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, QFrontendProcessMetaData> processes;
|
||||||
private Map<String, QFrontendAppMetaData> apps;
|
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
|
** Getter for appTree
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public List<QFrontendAppMetaData> getAppTree()
|
public List<AppTreeNode> getAppTree()
|
||||||
{
|
{
|
||||||
return appTree;
|
return appTree;
|
||||||
}
|
}
|
||||||
@ -104,7 +105,7 @@ public class MetaDataOutput extends AbstractActionOutput
|
|||||||
** Setter for appTree
|
** Setter for appTree
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void setAppTree(List<QFrontendAppMetaData> appTree)
|
public void setAppTree(List<AppTreeNode> appTree)
|
||||||
{
|
{
|
||||||
this.appTree = appTree;
|
this.appTree = appTree;
|
||||||
}
|
}
|
||||||
|
@ -26,17 +26,22 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
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)
|
@Target(ElementType.FIELD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface QField
|
public @interface QField
|
||||||
{
|
{
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
String label() default "";
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -51,4 +56,13 @@ public @interface QField
|
|||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
boolean isEditable() default true;
|
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.github.hervian.reflection.Fun;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
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.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.model.data.QRecordEntity;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
@ -120,10 +119,20 @@ public class QFieldMetaData
|
|||||||
setIsRequired(fieldAnnotation.isRequired());
|
setIsRequired(fieldAnnotation.isRequired());
|
||||||
setIsEditable(fieldAnnotation.isEditable());
|
setIsEditable(fieldAnnotation.isEditable());
|
||||||
|
|
||||||
|
if(StringUtils.hasContent(fieldAnnotation.label()))
|
||||||
|
{
|
||||||
|
setLabel(fieldAnnotation.label());
|
||||||
|
}
|
||||||
|
|
||||||
if(StringUtils.hasContent(fieldAnnotation.backendName()))
|
if(StringUtils.hasContent(fieldAnnotation.backendName()))
|
||||||
{
|
{
|
||||||
setBackendName(fieldAnnotation.backendName());
|
setBackendName(fieldAnnotation.backendName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(StringUtils.hasContent(fieldAnnotation.displayFormat()))
|
||||||
|
{
|
||||||
|
setDisplayFormat(fieldAnnotation.displayFormat());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(QException qe)
|
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
|
public enum AppTreeNodeType
|
||||||
{
|
{
|
||||||
|
@ -27,10 +27,6 @@ import java.util.List;
|
|||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
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.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)
|
@JsonInclude(Include.NON_NULL)
|
||||||
public class QFrontendAppMetaData
|
public class QFrontendAppMetaData
|
||||||
{
|
{
|
||||||
private AppTreeNodeType type;
|
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String label;
|
private String label;
|
||||||
|
|
||||||
private List<QFrontendAppMetaData> children = new ArrayList<>();
|
private List<AppTreeNode> children = new ArrayList<>();
|
||||||
|
|
||||||
private String iconName;
|
private String iconName;
|
||||||
|
|
||||||
@ -59,24 +53,7 @@ public class QFrontendAppMetaData
|
|||||||
this.name = appChildMetaData.getName();
|
this.name = appChildMetaData.getName();
|
||||||
this.label = appChildMetaData.getLabel();
|
this.label = appChildMetaData.getLabel();
|
||||||
|
|
||||||
if(appChildMetaData.getClass().equals(QTableMetaData.class))
|
if(appChildMetaData.getIcon() != null)
|
||||||
{
|
|
||||||
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()))
|
|
||||||
{
|
{
|
||||||
this.iconName = appChildMetaData.getIcon().getName();
|
this.iconName = appChildMetaData.getIcon().getName();
|
||||||
}
|
}
|
||||||
@ -106,22 +83,11 @@ public class QFrontendAppMetaData
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
** Getter for type
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public AppTreeNodeType getType()
|
|
||||||
{
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for children
|
** Getter for children
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public List<QFrontendAppMetaData> getChildren()
|
public List<AppTreeNode> getChildren()
|
||||||
{
|
{
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
@ -153,12 +119,12 @@ public class QFrontendAppMetaData
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void addChild(QFrontendAppMetaData qFrontendAppMetaData)
|
public void addChild(AppTreeNode childAppTreeNode)
|
||||||
{
|
{
|
||||||
if(children == null)
|
if(children == null)
|
||||||
{
|
{
|
||||||
children = new ArrayList<>();
|
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.QFrontendStepMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
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.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();
|
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.fields.QFieldMetaData;
|
||||||
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.StringUtils;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -78,7 +77,7 @@ public class QFrontendTableMetaData
|
|||||||
this.sections = tableMetaData.getSections();
|
this.sections = tableMetaData.getSections();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tableMetaData.getIcon() != null && StringUtils.hasContent(tableMetaData.getIcon().getName()))
|
if(tableMetaData.getIcon() != null)
|
||||||
{
|
{
|
||||||
this.iconName = tableMetaData.getIcon().getName();
|
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.
|
** 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
|
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
|
public class QAppMetaData implements QAppChildMetaData
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
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.QRecordEntity;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntityField;
|
import com.kingsrook.qqq.backend.core.model.data.QRecordEntityField;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
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
|
** Getter for parentAppName
|
||||||
**
|
**
|
||||||
|
@ -46,7 +46,7 @@ public class BasicETLLoadFunction implements BackendStep
|
|||||||
private static final Logger LOG = LogManager.getLogger(BasicETLLoadFunction.class);
|
private static final Logger LOG = LogManager.getLogger(BasicETLLoadFunction.class);
|
||||||
|
|
||||||
private QBackendTransaction transaction;
|
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 //
|
// run the query action as an async job //
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
AsyncJobManager asyncJobManager = new AsyncJobManager();
|
AsyncJobManager asyncJobManager = new AsyncJobManager();
|
||||||
String queryJobUUID = asyncJobManager.startJob("ReportAction>QueryAction", (status) ->
|
String queryJobUUID = asyncJobManager.startJob("StreamedETL>QueryAction", (status) ->
|
||||||
{
|
{
|
||||||
basicETLExtractFunction.run(runBackendStepInput, runBackendStepOutput);
|
basicETLExtractFunction.run(runBackendStepInput, runBackendStepOutput);
|
||||||
return (runBackendStepOutput);
|
return (runBackendStepOutput);
|
||||||
});
|
});
|
||||||
LOG.info("Started query job [" + queryJobUUID + "] for report");
|
LOG.info("Started query job [" + queryJobUUID + "] for streamed ETL");
|
||||||
|
|
||||||
AsyncJobState queryJobState = AsyncJobState.RUNNING;
|
AsyncJobState queryJobState = AsyncJobState.RUNNING;
|
||||||
AsyncJobStatus asyncJobStatus = null;
|
AsyncJobStatus asyncJobStatus = null;
|
||||||
@ -141,6 +141,14 @@ public class StreamedETLBackendStep implements BackendStep
|
|||||||
|
|
||||||
LOG.info("Query job [" + queryJobUUID + "] for ETL completed with status: " + asyncJobStatus);
|
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 //
|
// send the final records to transform & load steps //
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
@ -207,6 +215,7 @@ public class StreamedETLBackendStep implements BackendStep
|
|||||||
|
|
||||||
runBackendStepInput.setRecords(runBackendStepOutput.getRecords());
|
runBackendStepInput.setRecords(runBackendStepOutput.getRecords());
|
||||||
BasicETLLoadFunction basicETLLoadFunction = new BasicETLLoadFunction();
|
BasicETLLoadFunction basicETLLoadFunction = new BasicETLLoadFunction();
|
||||||
|
basicETLLoadFunction.setReturnStoredRecords(false);
|
||||||
basicETLLoadFunction.setTransaction(transaction);
|
basicETLLoadFunction.setTransaction(transaction);
|
||||||
basicETLLoadFunction.run(runBackendStepInput, runBackendStepOutput);
|
basicETLLoadFunction.run(runBackendStepInput, runBackendStepOutput);
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class ValueUtils
|
public class ValueUtils
|
||||||
{
|
{
|
||||||
private static final DateTimeFormatter yyyyMMddWithDashesFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
private static final DateTimeFormatter dateTimeFormatter_yyyyMMddWithDashes = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
private static final DateTimeFormatter MdyyyyWithSlashesFormatter = DateTimeFormatter.ofPattern("M/d/yyyy");
|
private static final DateTimeFormatter dateTimeFormatter_MdyyyyWithSlashes = DateTimeFormatter.ofPattern("M/d/yyyy");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ public class ValueUtils
|
|||||||
private static LocalDate tryLocalDateParsers(String s)
|
private static LocalDate tryLocalDateParsers(String s)
|
||||||
{
|
{
|
||||||
DateTimeParseException lastException = null;
|
DateTimeParseException lastException = null;
|
||||||
for(DateTimeFormatter dateTimeFormatter : List.of(yyyyMMddWithDashesFormatter, MdyyyyWithSlashesFormatter))
|
for(DateTimeFormatter dateTimeFormatter : List.of(dateTimeFormatter_yyyyMMddWithDashes, dateTimeFormatter_MdyyyyWithSlashes))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -386,7 +386,6 @@ public class ValueUtils
|
|||||||
}
|
}
|
||||||
else if(value instanceof Calendar c)
|
else if(value instanceof Calendar c)
|
||||||
{
|
{
|
||||||
TimeZone tz = c.getTimeZone();
|
|
||||||
return (c.toInstant());
|
return (c.toInstant());
|
||||||
}
|
}
|
||||||
else if(value instanceof LocalDateTime ldt)
|
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.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput;
|
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.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.QFrontendAppMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -84,7 +85,7 @@ class MetaDataActionTest
|
|||||||
|
|
||||||
QFrontendAppMetaData peopleApp = apps.get(TestUtils.APP_NAME_PEOPLE);
|
QFrontendAppMetaData peopleApp = apps.get(TestUtils.APP_NAME_PEOPLE);
|
||||||
assertThat(peopleApp.getChildren()).isNotEmpty();
|
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();
|
.filter(e -> e.getName().equals(TestUtils.APP_NAME_GREETINGS)).findFirst();
|
||||||
assertThat(greetingsAppUnderPeopleFromMapOptional).isPresent();
|
assertThat(greetingsAppUnderPeopleFromMapOptional).isPresent();
|
||||||
|
|
||||||
@ -97,18 +98,18 @@ class MetaDataActionTest
|
|||||||
///////////////////////////////////////////////
|
///////////////////////////////////////////////
|
||||||
// assert against the hierarchical apps tree //
|
// assert against the hierarchical apps tree //
|
||||||
///////////////////////////////////////////////
|
///////////////////////////////////////////////
|
||||||
List<QFrontendAppMetaData> appTree = result.getAppTree();
|
List<AppTreeNode> appTree = result.getAppTree();
|
||||||
Set<String> appNamesInTopOfTree = appTree.stream().map(QFrontendAppMetaData::getName).collect(Collectors.toSet());
|
Set<String> appNamesInTopOfTree = appTree.stream().map(AppTreeNode::getName).collect(Collectors.toSet());
|
||||||
assertThat(appNamesInTopOfTree).contains(TestUtils.APP_NAME_PEOPLE);
|
assertThat(appNamesInTopOfTree).contains(TestUtils.APP_NAME_PEOPLE);
|
||||||
assertThat(appNamesInTopOfTree).contains(TestUtils.APP_NAME_MISCELLANEOUS);
|
assertThat(appNamesInTopOfTree).contains(TestUtils.APP_NAME_MISCELLANEOUS);
|
||||||
assertThat(appNamesInTopOfTree).doesNotContain(TestUtils.APP_NAME_GREETINGS);
|
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();
|
.filter(e -> e.getName().equals(TestUtils.APP_NAME_PEOPLE)).findFirst();
|
||||||
assertThat(peopleAppOptional).isPresent();
|
assertThat(peopleAppOptional).isPresent();
|
||||||
assertThat(peopleAppOptional.get().getChildren()).isNotEmpty();
|
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();
|
.filter(e -> e.getName().equals(TestUtils.APP_NAME_GREETINGS)).findFirst();
|
||||||
assertThat(greetingsAppUnderPeopleFromTree).isPresent();
|
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.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.testentities.Item;
|
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.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.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.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
@ -177,6 +178,8 @@ class QRecordEntityTest
|
|||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// assert about attributes that came from @QField annotation //
|
// 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());
|
assertTrue(qTableMetaData.getField("sku").getIsRequired());
|
||||||
assertFalse(qTableMetaData.getField("quantity").getIsEditable());
|
assertFalse(qTableMetaData.getField("quantity").getIsEditable());
|
||||||
assertEquals("is_featured", qTableMetaData.getField("featured").getBackendName());
|
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 java.math.BigDecimal;
|
||||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
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.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
|
public class Item extends QRecordEntity
|
||||||
{
|
{
|
||||||
@QField(isRequired = true)
|
@QField(isRequired = true, label = "SKU")
|
||||||
private String sku;
|
private String sku;
|
||||||
|
|
||||||
@QField()
|
@QField()
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@QField(isEditable = false)
|
@QField(isEditable = false, displayFormat = DisplayFormat.COMMAS)
|
||||||
private Integer quantity;
|
private Integer quantity;
|
||||||
|
|
||||||
private BigDecimal price;
|
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
|
** 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
|
** re-checked, so it'll show as valid no matter what the token is.
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
@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
|
@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
|
** Test a token where last-checked is set to a time that would require it to be
|
||||||
** re-checked
|
** re-checked, so it'll show as invalid.
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@Test
|
@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
|
** Test a token where last-checked is past the threshold, so it'll get re-checked,
|
||||||
** re-checked
|
** and will fail.
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@Test
|
@Test
|
||||||
|
@ -55,7 +55,10 @@ class StreamedETLProcessTest
|
|||||||
|
|
||||||
RunProcessOutput result = new RunProcessAction().execute(request);
|
RunProcessOutput result = new RunProcessAction().execute(request);
|
||||||
assertNotNull(result);
|
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());
|
assertTrue(result.getException().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,12 +80,14 @@ class StreamedETLProcessTest
|
|||||||
// define our mapping from destination-table field names to source-table field names //
|
// define our mapping from destination-table field names to source-table field names //
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
QKeyBasedFieldMapping mapping = new QKeyBasedFieldMapping().withMapping("name", "firstName");
|
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));
|
request.addValue(StreamedETLProcess.FIELD_MAPPING_JSON, JsonUtils.toJson(mapping));
|
||||||
|
|
||||||
RunProcessOutput result = new RunProcessAction().execute(request);
|
RunProcessOutput result = new RunProcessAction().execute(request);
|
||||||
assertNotNull(result);
|
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());
|
assertTrue(result.getException().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,6 @@ class ValueUtilsTest
|
|||||||
@Test
|
@Test
|
||||||
void testGetValueAsString() throws QValueException
|
void testGetValueAsString() throws QValueException
|
||||||
{
|
{
|
||||||
//noinspection ConstantConditions
|
|
||||||
assertNull(ValueUtils.getValueAsString(null));
|
assertNull(ValueUtils.getValueAsString(null));
|
||||||
assertEquals("", ValueUtils.getValueAsString(""));
|
assertEquals("", ValueUtils.getValueAsString(""));
|
||||||
assertEquals(" ", ValueUtils.getValueAsString(" "));
|
assertEquals(" ", ValueUtils.getValueAsString(" "));
|
||||||
@ -164,26 +163,28 @@ class ValueUtilsTest
|
|||||||
@Test
|
@Test
|
||||||
void testGetValueAsLocalDate() throws QValueException
|
void testGetValueAsLocalDate() throws QValueException
|
||||||
{
|
{
|
||||||
|
LocalDate expected = LocalDate.of(1980, Month.MAY, 31);
|
||||||
|
|
||||||
assertNull(ValueUtils.getValueAsLocalDate(null));
|
assertNull(ValueUtils.getValueAsLocalDate(null));
|
||||||
assertNull(ValueUtils.getValueAsLocalDate(""));
|
assertNull(ValueUtils.getValueAsLocalDate(""));
|
||||||
assertNull(ValueUtils.getValueAsLocalDate(" "));
|
assertNull(ValueUtils.getValueAsLocalDate(" "));
|
||||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(LocalDate.of(1980, 5, 31)));
|
assertEquals(expected, 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(new java.sql.Date(80, 4, 31)));
|
||||||
//noinspection MagicConstant
|
//noinspection MagicConstant
|
||||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new java.util.Date(80, 4, 31)));
|
assertEquals(expected, 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(expected, 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(expected, 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(expected, 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, Calendar.MAY, 31, 22, 0)));
|
||||||
//noinspection MagicConstant
|
//noinspection MagicConstant
|
||||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, 4, 31)));
|
assertEquals(expected, ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, 4, 31)));
|
||||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate(new GregorianCalendar(1980, Calendar.MAY, 31)));
|
assertEquals(expected, 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(expected, 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(expected, 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(expected, 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(expected, ValueUtils.getValueAsLocalDate(LocalDateTime.of(1980, Month.MAY, 31, 12, 0)));
|
||||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate("1980-05-31"));
|
assertEquals(expected, ValueUtils.getValueAsLocalDate("1980-05-31"));
|
||||||
assertEquals(LocalDate.of(1980, Month.MAY, 31), ValueUtils.getValueAsLocalDate("05/31/1980"));
|
assertEquals(expected, ValueUtils.getValueAsLocalDate("05/31/1980"));
|
||||||
|
|
||||||
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a"));
|
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a"));
|
||||||
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a,b"));
|
assertThrows(QValueException.class, () -> ValueUtils.getValueAsLocalDate("a,b"));
|
||||||
|
@ -172,8 +172,6 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
|
|||||||
{
|
{
|
||||||
LOG.info("Opening transaction");
|
LOG.info("Opening transaction");
|
||||||
Connection connection = getConnection(insertInput);
|
Connection connection = getConnection(insertInput);
|
||||||
connection.setAutoCommit(false);
|
|
||||||
System.out.println("Set connection [" + connection + "] to auto-commit false");
|
|
||||||
|
|
||||||
return (new RDBMSTransaction(connection));
|
return (new RDBMSTransaction(connection));
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -46,8 +46,9 @@ public class RDBMSTransaction extends QBackendTransaction
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public RDBMSTransaction(Connection connection)
|
public RDBMSTransaction(Connection connection) throws SQLException
|
||||||
{
|
{
|
||||||
|
connection.setAutoCommit(false);
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +74,6 @@ public class RDBMSTransaction extends QBackendTransaction
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
RDBMSTransaction.LOG.info("Committing transaction");
|
RDBMSTransaction.LOG.info("Committing transaction");
|
||||||
System.out.println("Calling commit on connection [" + connection + "]");
|
|
||||||
connection.commit();
|
connection.commit();
|
||||||
RDBMSTransaction.LOG.info("Commit complete");
|
RDBMSTransaction.LOG.info("Commit complete");
|
||||||
}
|
}
|
||||||
@ -108,18 +108,7 @@ public class RDBMSTransaction extends 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
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.module.rdbms.jdbc;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
@ -188,8 +189,6 @@ public class QueryManager
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T executeStatementForSingleValue(Connection connection, Class<T> returnClass, String sql, Object... params) throws SQLException
|
public static <T> T executeStatementForSingleValue(Connection connection, Class<T> returnClass, String sql, Object... params) throws SQLException
|
||||||
{
|
{
|
||||||
throw (new NotImplementedException());
|
|
||||||
/*
|
|
||||||
PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params);
|
PreparedStatement statement = prepareStatementAndBindParams(connection, sql, params);
|
||||||
statement.execute();
|
statement.execute();
|
||||||
ResultSet resultSet = statement.getResultSet();
|
ResultSet resultSet = statement.getResultSet();
|
||||||
@ -238,7 +237,6 @@ public class QueryManager
|
|||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1397,6 +1395,38 @@ public class QueryManager
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static Instant getInstant(ResultSet resultSet, String column) throws SQLException
|
||||||
|
{
|
||||||
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
|
if(resultSet.wasNull())
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (value.toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static Instant getInstant(ResultSet resultSet, int column) throws SQLException
|
||||||
|
{
|
||||||
|
Timestamp value = resultSet.getTimestamp(column);
|
||||||
|
if(resultSet.wasNull())
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (value.toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -22,14 +22,22 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms;
|
package com.kingsrook.qqq.backend.module.rdbms;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.List;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
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.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSActionTest;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -42,6 +50,29 @@ public class TestUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void primeTestDatabase(String sqlFileName) throws Exception
|
||||||
|
{
|
||||||
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
|
try(Connection connection = connectionManager.getConnection(TestUtils.defineBackend()))
|
||||||
|
{
|
||||||
|
InputStream primeTestDatabaseSqlStream = RDBMSActionTest.class.getResourceAsStream("/" + sqlFileName);
|
||||||
|
assertNotNull(primeTestDatabaseSqlStream);
|
||||||
|
List<String> lines = (List<String>) IOUtils.readLines(primeTestDatabaseSqlStream);
|
||||||
|
lines = lines.stream().filter(line -> !line.startsWith("-- ")).toList();
|
||||||
|
String joinedSQL = String.join("\n", lines);
|
||||||
|
for(String sql : joinedSQL.split(";"))
|
||||||
|
{
|
||||||
|
QueryManager.executeUpdate(connection, sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -22,15 +22,11 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
package com.kingsrook.qqq.backend.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.util.List;
|
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import static junit.framework.Assert.assertNotNull;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -57,33 +53,11 @@ public class RDBMSActionTest
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
protected void primeTestDatabase() throws Exception
|
protected void primeTestDatabase() throws Exception
|
||||||
{
|
{
|
||||||
primeTestDatabase("prime-test-database.sql");
|
TestUtils.primeTestDatabase("prime-test-database.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void primeTestDatabase(String sqlFileName) throws Exception
|
|
||||||
{
|
|
||||||
ConnectionManager connectionManager = new ConnectionManager();
|
|
||||||
try(Connection connection = connectionManager.getConnection(TestUtils.defineBackend()))
|
|
||||||
{
|
|
||||||
InputStream primeTestDatabaseSqlStream = RDBMSActionTest.class.getResourceAsStream("/" + sqlFileName);
|
|
||||||
assertNotNull(primeTestDatabaseSqlStream);
|
|
||||||
List<String> lines = (List<String>) IOUtils.readLines(primeTestDatabaseSqlStream);
|
|
||||||
lines = lines.stream().filter(line -> !line.startsWith("-- ")).toList();
|
|
||||||
String joinedSQL = String.join("\n", lines);
|
|
||||||
for(String sql : joinedSQL.split(";"))
|
|
||||||
{
|
|
||||||
QueryManager.executeUpdate(connection, sql);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
|
@ -151,7 +151,7 @@ public class RDBMSDeleteActionTest extends RDBMSActionTest
|
|||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
// load the parent-child tables, with foreign keys and instance //
|
// load the parent-child tables, with foreign keys and instance //
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
super.primeTestDatabase("prime-test-database-parent-child-tables.sql");
|
TestUtils.primeTestDatabase("prime-test-database-parent-child-tables.sql");
|
||||||
DeleteInput deleteInput = initChildTableInstanceAndDeleteRequest();
|
DeleteInput deleteInput = initChildTableInstanceAndDeleteRequest();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* 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.module.rdbms.actions;
|
||||||
|
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager;
|
||||||
|
import com.kingsrook.qqq.backend.module.rdbms.jdbc.QueryManager;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for RDBMSTransaction
|
||||||
|
*******************************************************************************/
|
||||||
|
class RDBMSTransactionTest
|
||||||
|
{
|
||||||
|
private final String testToken = getClass().getName();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@BeforeEach
|
||||||
|
protected void beforeEach() throws Exception
|
||||||
|
{
|
||||||
|
TestUtils.primeTestDatabase("prime-test-database.sql");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testCommit() throws Exception
|
||||||
|
{
|
||||||
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
|
Connection connection = connectionManager.getConnection(TestUtils.defineBackend());
|
||||||
|
Integer preCount = QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT COUNT(*) FROM person");
|
||||||
|
|
||||||
|
Connection connectionForTransaction = connectionManager.getConnection(TestUtils.defineBackend());
|
||||||
|
RDBMSTransaction transaction = new RDBMSTransaction(connectionForTransaction);
|
||||||
|
|
||||||
|
QueryManager.executeUpdate(transaction.getConnection(), "INSERT INTO person (first_name, last_name, email) VALUES (?, ?, ?)", testToken, testToken, testToken);
|
||||||
|
transaction.commit();
|
||||||
|
|
||||||
|
Integer postCount = QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT COUNT(*) FROM person");
|
||||||
|
assertEquals(preCount + 1, postCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testRollback() throws Exception
|
||||||
|
{
|
||||||
|
ConnectionManager connectionManager = new ConnectionManager();
|
||||||
|
Connection connection = connectionManager.getConnection(TestUtils.defineBackend());
|
||||||
|
Integer preCount = QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT COUNT(*) FROM person");
|
||||||
|
|
||||||
|
Connection connectionForTransaction = connectionManager.getConnection(TestUtils.defineBackend());
|
||||||
|
RDBMSTransaction transaction = new RDBMSTransaction(connectionForTransaction);
|
||||||
|
|
||||||
|
QueryManager.executeUpdate(transaction.getConnection(), "INSERT INTO person (first_name, last_name, email) VALUES (?, ?, ?)", testToken, testToken, testToken);
|
||||||
|
transaction.rollback();
|
||||||
|
|
||||||
|
Integer postCount = QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT COUNT(*) FROM person");
|
||||||
|
assertEquals(preCount, postCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -329,4 +329,35 @@ class QueryManagerTest
|
|||||||
assertEquals(59, localTime.getSecond(), "Second value");
|
assertEquals(59, localTime.getSecond(), "Second value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testExecuteStatementForSingleValue() throws SQLException
|
||||||
|
{
|
||||||
|
Connection connection = getConnection();
|
||||||
|
QueryManager.executeUpdate(connection, """
|
||||||
|
INSERT INTO test_table
|
||||||
|
( int_col, datetime_col, char_col, date_col, time_col )
|
||||||
|
VALUES
|
||||||
|
( 47, '2022-08-10 19:22:08', 'Q', '2022-08-10', '19:22:08')
|
||||||
|
""");
|
||||||
|
assertEquals(null, QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT int_col FROM test_table WHERE int_col = -1"));
|
||||||
|
assertEquals(1, QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT COUNT(*) FROM test_table"));
|
||||||
|
assertEquals(47, QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT int_col FROM test_table"));
|
||||||
|
assertEquals("Q", QueryManager.executeStatementForSingleValue(connection, String.class, "SELECT char_col FROM test_table"));
|
||||||
|
assertEquals(new BigDecimal("1.1"), QueryManager.executeStatementForSingleValue(connection, BigDecimal.class, "SELECT 1.1 FROM test_table"));
|
||||||
|
assertEquals(1, QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT 1.1 FROM test_table"));
|
||||||
|
|
||||||
|
QueryManager.executeUpdate(connection, """
|
||||||
|
INSERT INTO test_table
|
||||||
|
( int_col, datetime_col, char_col, date_col, time_col )
|
||||||
|
VALUES
|
||||||
|
( null, null, null, null, null)
|
||||||
|
""");
|
||||||
|
assertEquals(null, QueryManager.executeStatementForSingleValue(connection, Integer.class, "SELECT int_col FROM test_table WHERE int_col IS NULL"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -26,6 +26,7 @@ import java.util.List;
|
|||||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
@ -227,7 +228,7 @@ public class SampleMetaDataProvider
|
|||||||
table.addField(new QFieldMetaData("company_code", QFieldType.STRING) // todo PVS
|
table.addField(new QFieldMetaData("company_code", QFieldType.STRING) // todo PVS
|
||||||
.withLabel("Company")
|
.withLabel("Company")
|
||||||
.withIsRequired(true)
|
.withIsRequired(true)
|
||||||
.withBackendName("comp_code"));
|
.withBackendName("company_code"));
|
||||||
|
|
||||||
table.addField(new QFieldMetaData("service_level", QFieldType.STRING) // todo PVS
|
table.addField(new QFieldMetaData("service_level", QFieldType.STRING) // todo PVS
|
||||||
.withLabel("Service Level")
|
.withLabel("Service Level")
|
||||||
@ -246,7 +247,7 @@ public class SampleMetaDataProvider
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static QTableMetaData defineTablePerson()
|
public static QTableMetaData defineTablePerson()
|
||||||
{
|
{
|
||||||
return new QTableMetaData()
|
QTableMetaData qTableMetaData = new QTableMetaData()
|
||||||
.withName(TABLE_NAME_PERSON)
|
.withName(TABLE_NAME_PERSON)
|
||||||
.withLabel("Person")
|
.withLabel("Person")
|
||||||
.withBackendName(RDBMS_BACKEND_NAME)
|
.withBackendName(RDBMS_BACKEND_NAME)
|
||||||
@ -266,9 +267,11 @@ public class SampleMetaDataProvider
|
|||||||
.withSection(new QFieldSection("identity", "Identity", new QIcon("badge"), Tier.T1, List.of("id", "firstName", "lastName")))
|
.withSection(new QFieldSection("identity", "Identity", new QIcon("badge"), Tier.T1, List.of("id", "firstName", "lastName")))
|
||||||
.withSection(new QFieldSection("basicInfo", "Basic Info", new QIcon("dataset"), Tier.T2, List.of("email", "birthDate")))
|
.withSection(new QFieldSection("basicInfo", "Basic Info", new QIcon("dataset"), Tier.T2, List.of("email", "birthDate")))
|
||||||
.withSection(new QFieldSection("employmentInfo", "Employment Info", new QIcon("work"), Tier.T2, List.of("annualSalary", "daysWorked")))
|
.withSection(new QFieldSection("employmentInfo", "Employment Info", new QIcon("work"), Tier.T2, List.of("annualSalary", "daysWorked")))
|
||||||
.withSection(new QFieldSection("dates", "Dates", new QIcon("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")))
|
.withSection(new QFieldSection("dates", "Dates", new QIcon("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));
|
||||||
|
|
||||||
.withInferredFieldBackendNames();
|
QInstanceEnricher.setInferredFieldBackendNames(qTableMetaData);
|
||||||
|
|
||||||
|
return (qTableMetaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user