Compare commits

...

42 Commits

Author SHA1 Message Date
6702c06ed0 Merge branch 'rel/0.21.0' 2024-08-23 11:47:47 -05:00
9dfbd839c8 Update versions for release 2024-08-23 11:39:07 -05:00
724d5779cc Merge pull request #127 from Kingsrook/feature/CE-1405-zero-day-ledger-billing
Feature/ce 1405 zero day ledger billing
2024-08-23 11:19:46 -05:00
1fef376e65 Merge pull request #128 from Kingsrook/feature/CE-1556-ops-overview-enhanced-tooltips
Feature/ce 1556 ops overview enhanced tooltips
2024-08-23 11:02:05 -05:00
d3417a0652 CE-1405 Remove usage of SparseQRecord... not clear if we want it or not at this time 2024-08-21 20:09:36 -05:00
053d5f1058 CE-1405 Add getOldRecordMap 2024-08-21 17:01:55 -05:00
47e27d5ffc CE-1554: updates to allow widget block overlays 2024-08-20 18:06:01 -05:00
59a70a4cb7 CE-1405 fix bug with fieldNamesToInclude for tables w/ no selected fields 2024-08-20 09:38:54 -05:00
fea757c46d Merged dev into feature/CE-1405-zero-day-ledger-billing 2024-08-16 16:57:26 -05:00
9a65ea81b2 CE-1405 / CE-1479 - add queryInput.fieldNamesToInclude 2024-08-15 08:53:19 -05:00
494ec00b84 CE-1556: updated to try to use composite block data within tooltips 2024-08-13 17:23:30 -05:00
9b4b61af38 Merged feature/CE-1472-add-extensivewms-orders into dev 2024-08-13 10:14:46 -05:00
f237b5e82d Merged feature/fix-formParam-exceptions-for-plaintext-body-with-percent into dev 2024-08-05 13:36:43 -05:00
207311eb0b Merged feature/qol-improvements-20240801 into dev 2024-08-05 13:36:24 -05:00
ab5af234af Merged feature/checkstyle-updates into dev 2024-08-05 13:35:21 -05:00
9baa7c32bf Add safety around most calls to formParam and/or queryParam, as they can throw if the request isn't formatted as expected, in ways that we may not want it to. 2024-08-02 12:32:36 -05:00
3eae3a5758 re-set queryStat startTimestamp to just before executeQuery, to avoid including time spent aquiring db connection 2024-08-01 15:12:59 -05:00
a11d584c8a Fix formatting of booleans when value is string (e.g., format based on QFieldMetaData type, not value object class) 2024-08-01 15:11:20 -05:00
ba3cf53c30 Update to throw QNotFoundException if view isn't found by id (rather than NPE) 2024-08-01 15:08:53 -05:00
d44790545d Add total # failures to message; remove unused c'tor 2024-08-01 15:04:03 -05:00
5aed59b9b1 Add implements AutoCloseable, so we could use in a try-with-resources 2024-08-01 15:02:38 -05:00
3bcc0a17bc Add a log info re: releasing lock 2024-08-01 15:02:20 -05:00
09c4d99612 Avoid NPE and return w/ noop in performValidations if null (or empty) input records 2024-08-01 15:02:06 -05:00
26fc4fb4e0 Initial checkin 2024-08-01 15:01:22 -05:00
d92be4e69b don't duplicate apikey=value in re-tries; mask api key in outboundApiLog urls 2024-08-01 15:00:36 -05:00
2de3306f95 Add c'tor that takes table name, and override withTableName 2024-08-01 14:41:55 -05:00
58b0936c50 Add details to Incorrect number of values given exception 2024-08-01 14:41:40 -05:00
51eb7d89be Take report format as input 2024-08-01 14:40:27 -05:00
0b5e97d596 Bugfix, where sheet contents could get out-of-sync with their labels (e.g., see use-case with some summary views before their corresponding table views) 2024-07-22 14:26:45 -05:00
2609bc801c CE-1405 Add dataSource as argument to ReportCustomRecordSourceInterface.execute 2024-07-22 14:25:49 -05:00
583d702355 Re-add getInstance and getSession (until qqq consumer apps stop using them) 2024-07-19 17:02:37 -05:00
06a69279a8 CE-1472 - Fix doUpdate to set URL 2024-07-19 16:38:06 -05:00
9a2276edf2 CE-1472 - Refactored to do variants a little more generically per different auth-types; made createOAuth2TokenRequest its own overrideable method 2024-07-19 16:38:06 -05:00
36307dba24 CE-1405 Updates to qqq-reports: support for ReportCustomRecordSourceInterface 2024-07-19 16:37:22 -05:00
fa2b1c0b8e Fix merge conflicts 2024-07-19 16:25:15 -05:00
840e1aada3 Applying checkstyle updates to test sources 2024-07-19 16:16:51 -05:00
22d5bc547c Add includeTestSourceDirectory=true to checkstyle config 2024-07-19 16:16:51 -05:00
b7cfea157d Checkstyle updates
- remove MagicNumber
- add MissingJavadocType
- remove rules about contents of javadocs
2024-07-19 16:16:51 -05:00
028751e23a more test coverage for javalin (for new anonymous inner TypeReference) 2024-07-19 16:16:27 -05:00
be0e1f9c0b add some test coverage (updates to eliminate warnings put us just under threshold) 2024-07-19 16:16:27 -05:00
912e40fe0b Eliminated all warnings. 2024-07-19 16:16:27 -05:00
f9af2ba983 Remove all calls to actionInput.getInstance and getSesssion, in favor of the equivallent methods from QContext 2024-07-19 16:16:16 -05:00
200 changed files with 3035 additions and 809 deletions

View File

@ -213,18 +213,6 @@
<property name="tokens" value="VARIABLE_DEF"/> <property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/> <property name="allowSamelineMultipleAnnotations" value="true"/>
</module> </module>
<module name="NonEmptyAtclauseDescription"/>
<!-- <module name="JavadocTagContinuationIndentation"/> -->
<!--
<module name="SummaryJavadoc">
<property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module>
-->
<!-- <module name="JavadocParagraph"/> -->
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module>
<module name="JavadocMethod"> <module name="JavadocMethod">
<property name="allowMissingParamTags" value="true"/> <property name="allowMissingParamTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/> <property name="allowMissingReturnTag" value="true"/>
@ -233,23 +221,14 @@
<module name="MissingJavadocMethod"> <module name="MissingJavadocMethod">
<property name="scope" value="private"/> <property name="scope" value="private"/>
</module> </module>
<module name="MissingJavadocType">
<property name="scope" value="private"/>
</module>
<module name="MethodName"> <module name="MethodName">
<property name="format" value="^[a-z][a-zA-Z0-9_]*$"/> <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
<message key="name.invalidPattern" <message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/> value="Method name ''{0}'' must match pattern ''{1}''."/>
</module> </module>
<module name="SingleLineJavadoc">
<property name="ignoreInlineTags" value="false"/>
</module>
<module name="MagicNumber">
<property name="severity" value="info"/>
<property name="tokens" value="NUM_DOUBLE, NUM_FLOAT, NUM_INT"/>
<property name="ignoreNumbers" value="0, 1, 2, 3, 4, 5, 6, 7, 8"/>
<property name="ignoreFieldDeclaration" value="true"/>
<property name="ignoreAnnotation" value="true"/>
</module>
<module name="EmptyCatchBlock"> <module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/> <property name="exceptionVariableName" value="expected"/>
</module> </module>

View File

@ -33,9 +33,6 @@ If the {link-table} has a `POST_QUERY_CUSTOMIZER` defined, then after records ar
* `table` - *String, Required* - Name of the table being queried against. * `table` - *String, Required* - Name of the table being queried against.
* `filter` - *<<QQueryFilter>> object* - Specification for what records should be returned, based on *<<QFilterCriteria>>* objects, and how they should be sorted, based on *<<QFilterOrderBy>>* objects. * `filter` - *<<QQueryFilter>> object* - Specification for what records should be returned, based on *<<QFilterCriteria>>* objects, and how they should be sorted, based on *<<QFilterOrderBy>>* objects.
If a `filter` is not given, then all rows in the table will be returned by the query. If a `filter` is not given, then all rows in the table will be returned by the query.
* `skip` - *Integer* - Optional number of records to be skipped at the beginning of the result set.
e.g., for implementing pagination.
* `limit` - *Integer* - Optional maximum number of records to be returned by the query.
* `transaction` - *QBackendTransaction object* - Optional transaction object. * `transaction` - *QBackendTransaction object* - Optional transaction object.
** Behavior for this object is backend-dependant. ** Behavior for this object is backend-dependant.
In an RDBMS backend, this object is generally needed if you want your query to see data that may have been modified within the same transaction. In an RDBMS backend, this object is generally needed if you want your query to see data that may have been modified within the same transaction.
@ -55,6 +52,14 @@ But if running a query to provide data as part of a process, then this can gener
* `shouldMaskPassword` - *boolean, default: true* - Controls whether or not fields with `type` = `PASSWORD` should be masked, or if their actual values should be returned. * `shouldMaskPassword` - *boolean, default: true* - Controls whether or not fields with `type` = `PASSWORD` should be masked, or if their actual values should be returned.
* `queryJoins` - *List of <<QueryJoin>> objects* - Optional list of tables to be joined with the main table being queried. * `queryJoins` - *List of <<QueryJoin>> objects* - Optional list of tables to be joined with the main table being queried.
See QueryJoin below for further details. See QueryJoin below for further details.
* `fieldNamesToInclude` - *Set of String* - Optional set of field names to be included in the records.
** Fields from a queryJoin must be prefixed by the join table's name or alias, and a period.
Field names from the table being queried should not have any sort of prefix.
** A `null` set here (default) means to include all fields from the table and any queryJoins set as select=true.
** An empty set will cause an error, as well any unrecognized field names.
** `QueryAction` will validate the set of field names, and throw an exception if any unrecognized names are given.
** _Note that this is an optional feature, which some backend modules may not implement.
Meaning, they would always return all fields._
==== QQueryFilter ==== QQueryFilter
A key component of *<<QueryInput>>*, a *QQueryFilter* defines both what records should be included in a query's results (e.g., an SQL `WHERE`), as well as how those results should be sorted (SQL `ORDER BY`). A key component of *<<QueryInput>>*, a *QQueryFilter* defines both what records should be included in a query's results (e.g., an SQL `WHERE`), as well as how those results should be sorted (SQL `ORDER BY`).
@ -68,6 +73,9 @@ In general, multiple *orderBys* can be given (depending on backend implementatio
** Each *subFilter* can include its own additional *subFilters*. ** Each *subFilter* can include its own additional *subFilters*.
** Each *subFilter* can specify a different *booleanOperator*. ** Each *subFilter* can specify a different *booleanOperator*.
** For example, consider the following *QQueryFilter*, that uses two *subFilters*, and a mix of *booleanOperators* ** For example, consider the following *QQueryFilter*, that uses two *subFilters*, and a mix of *booleanOperators*
* `skip` - *Integer* - Optional number of records to be skipped at the beginning of the result set.
e.g., for implementing pagination.
* `limit` - *Integer* - Optional maximum number of records to be returned by the query.
[source,java] [source,java]
---- ----

View File

@ -46,12 +46,11 @@
</modules> </modules>
<properties> <properties>
<revision>0.21.0-SNAPSHOT</revision> <revision>0.21.0</revision>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.release>17</maven.compiler.release>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.showDeprecation>true</maven.compiler.showDeprecation> <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
<maven.compiler.showWarnings>true</maven.compiler.showWarnings> <maven.compiler.showWarnings>true</maven.compiler.showWarnings>
<coverage.haltOnFailure>true</coverage.haltOnFailure> <coverage.haltOnFailure>true</coverage.haltOnFailure>
@ -168,6 +167,7 @@
<violationSeverity>warning</violationSeverity> <violationSeverity>warning</violationSeverity>
<excludes>**/target/generated-sources/*.*</excludes> <excludes>**/target/generated-sources/*.*</excludes>
<!-- <linkXRef>false</linkXRef> --> <!-- <linkXRef>false</linkXRef> -->
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration> </configuration>
<goals> <goals>
<goal>check</goal> <goal>check</goal>

View File

@ -37,7 +37,7 @@ import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
** **
** Note: One would imagine that this class shouldn't ever implement Serializable... ** Note: One would imagine that this class shouldn't ever implement Serializable...
*******************************************************************************/ *******************************************************************************/
public class QBackendTransaction public class QBackendTransaction implements AutoCloseable
{ {
/******************************************************************************* /*******************************************************************************

View File

@ -344,6 +344,9 @@ public class RecordAutomationStatusUpdater
/***************************************************************************
**
***************************************************************************/
private record Key(QTableMetaData table, TriggerEvent triggerEvent) {} private record Key(QTableMetaData table, TriggerEvent triggerEvent) {}
} }

View File

@ -55,10 +55,10 @@ public abstract class AbstractPreInsertCustomizer implements TableCustomizerInte
///////////////////////////////////////////////////////////////////////////////// /***************************************************************************
// allow the customizer to specify when it should be executed as part of the // ** allow the customizer to specify when it should be executed as part of the
// insert action. default (per method in this class) is AFTER_ALL_VALIDATIONS // ** insert action. default (per method in this class) is AFTER_ALL_VALIDATIONS
///////////////////////////////////////////////////////////////////////////////// ***************************************************************************/
public enum WhenToRun public enum WhenToRun
{ {
BEFORE_ALL_VALIDATIONS, BEFORE_ALL_VALIDATIONS,

View File

@ -28,6 +28,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException; import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
@ -49,6 +50,9 @@ import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
*******************************************************************************/ *******************************************************************************/
public abstract class ChildInserterPostInsertCustomizer extends AbstractPostInsertCustomizer public abstract class ChildInserterPostInsertCustomizer extends AbstractPostInsertCustomizer
{ {
/***************************************************************************
**
***************************************************************************/
public enum RelationshipType public enum RelationshipType
{ {
PARENT_POINTS_AT_CHILD, PARENT_POINTS_AT_CHILD,
@ -97,7 +101,7 @@ public abstract class ChildInserterPostInsertCustomizer extends AbstractPostInse
List<QRecord> rs = records; List<QRecord> rs = records;
List<QRecord> childrenToInsert = new ArrayList<>(); List<QRecord> childrenToInsert = new ArrayList<>();
QTableMetaData table = getInsertInput().getTable(); QTableMetaData table = getInsertInput().getTable();
QTableMetaData childTable = getInsertInput().getInstance().getTable(getChildTableName()); QTableMetaData childTable = QContext.getQInstance().getTable(getChildTableName());
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// iterate over the inserted records, building a list child records to insert // // iterate over the inserted records, building a list child records to insert //

View File

@ -24,10 +24,12 @@ package com.kingsrook.qqq.backend.core.actions.customizers;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
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.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
@ -143,4 +145,19 @@ public interface RecordCustomizerUtilityInterface
} }
} }
/*******************************************************************************
**
*******************************************************************************/
default Map<Serializable, QRecord> getOldRecordMap(List<QRecord> oldRecordList, UpdateInput updateInput)
{
Map<Serializable, QRecord> oldRecordMap = new HashMap<>();
for(QRecord qRecord : oldRecordList)
{
oldRecordMap.put(qRecord.getValue(updateInput.getTable().getPrimaryKeyField()), qRecord);
}
return (oldRecordMap);
}
} }

View File

@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.actions.values.SearchPossibleValueSourceAction; import com.kingsrook.qqq.backend.core.actions.values.SearchPossibleValueSourceAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
@ -102,7 +103,7 @@ public abstract class AbstractWidgetRenderer
String possibleValueSourceName = dropdownData.getPossibleValueSourceName(); String possibleValueSourceName = dropdownData.getPossibleValueSourceName();
if(possibleValueSourceName != null) if(possibleValueSourceName != null)
{ {
QPossibleValueSource possibleValueSource = input.getInstance().getPossibleValueSource(possibleValueSourceName); QPossibleValueSource possibleValueSource = QContext.getQInstance().getPossibleValueSource(possibleValueSourceName);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// this looks complicated, but is just look for a label in the dropdown data and if found use it, // // this looks complicated, but is just look for a label in the dropdown data and if found use it, //

View File

@ -34,6 +34,7 @@ import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException; import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
@ -181,10 +182,10 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
{ {
String widgetLabel = input.getQueryParams().get("widgetLabel"); String widgetLabel = input.getQueryParams().get("widgetLabel");
String joinName = input.getQueryParams().get("joinName"); String joinName = input.getQueryParams().get("joinName");
QJoinMetaData join = input.getInstance().getJoin(joinName); QJoinMetaData join = QContext.getQInstance().getJoin(joinName);
String id = input.getQueryParams().get("id"); String id = input.getQueryParams().get("id");
QTableMetaData leftTable = input.getInstance().getTable(join.getLeftTable()); QTableMetaData leftTable = QContext.getQInstance().getTable(join.getLeftTable());
QTableMetaData rightTable = input.getInstance().getTable(join.getRightTable()); QTableMetaData rightTable = QContext.getQInstance().getTable(join.getRightTable());
Integer maxRows = null; Integer maxRows = null;
if(StringUtils.hasContent(input.getQueryParams().get("maxRows"))) if(StringUtils.hasContent(input.getQueryParams().get("maxRows")))
@ -252,7 +253,7 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
} }
} }
String tablePath = input.getInstance().getTablePath(rightTable.getName()); String tablePath = QContext.getQInstance().getTablePath(rightTable.getName());
String viewAllLink = tablePath == null ? null : (tablePath + "?filter=" + URLEncoder.encode(JsonUtils.toJson(filter), Charset.defaultCharset())); String viewAllLink = tablePath == null ? null : (tablePath + "?filter=" + URLEncoder.encode(JsonUtils.toJson(filter), Charset.defaultCharset()));
ChildRecordListData widgetData = new ChildRecordListData(widgetLabel, queryOutput, rightTable, tablePath, viewAllLink, totalRows); ChildRecordListData widgetData = new ChildRecordListData(widgetLabel, queryOutput, rightTable, tablePath, viewAllLink, totalRows);
@ -278,7 +279,9 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
Map<String, Serializable> widgetValues = input.getWidgetMetaData().getDefaultValues(); Map<String, Serializable> widgetValues = input.getWidgetMetaData().getDefaultValues();
if(widgetValues.containsKey("disabledFieldsForNewChildRecords")) if(widgetValues.containsKey("disabledFieldsForNewChildRecords"))
{ {
widgetData.setDisabledFieldsForNewChildRecords((Set<String>) widgetValues.get("disabledFieldsForNewChildRecords")); @SuppressWarnings("unchecked")
Set<String> disabledFieldsForNewChildRecords = (Set<String>) widgetValues.get("disabledFieldsForNewChildRecords");
widgetData.setDisabledFieldsForNewChildRecords(disabledFieldsForNewChildRecords);
} }
else else
{ {

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
import java.util.HashMap; import java.util.HashMap;
import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput; import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput; import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
@ -57,7 +58,7 @@ public class ProcessWidgetRenderer extends AbstractWidgetRenderer
setupDropdowns(input, widgetMetaData, data); setupDropdowns(input, widgetMetaData, data);
String processName = (String) widgetMetaData.getDefaultValues().get(WIDGET_PROCESS_NAME); String processName = (String) widgetMetaData.getDefaultValues().get(WIDGET_PROCESS_NAME);
QProcessMetaData processMetaData = input.getInstance().getProcess(processName); QProcessMetaData processMetaData = QContext.getQInstance().getProcess(processName);
data.setProcessMetaData(processMetaData); data.setProcessMetaData(processMetaData);
data.setDefaultValues(new HashMap<>(input.getQueryParams())); data.setDefaultValues(new HashMap<>(input.getQueryParams()));

View File

@ -30,6 +30,7 @@ import java.util.Map;
import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionCheckResult; import com.kingsrook.qqq.backend.core.actions.permissions.PermissionCheckResult;
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper; import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
import com.kingsrook.qqq.backend.core.context.QContext;
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;
@ -72,7 +73,7 @@ public class MetaDataAction
// map tables to frontend metadata // // map tables to frontend metadata //
///////////////////////////////////// /////////////////////////////////////
Map<String, QFrontendTableMetaData> tables = new LinkedHashMap<>(); Map<String, QFrontendTableMetaData> tables = new LinkedHashMap<>();
for(Map.Entry<String, QTableMetaData> entry : metaDataInput.getInstance().getTables().entrySet()) for(Map.Entry<String, QTableMetaData> entry : QContext.getQInstance().getTables().entrySet())
{ {
String tableName = entry.getKey(); String tableName = entry.getKey();
QTableMetaData table = entry.getValue(); QTableMetaData table = entry.getValue();
@ -83,7 +84,7 @@ public class MetaDataAction
continue; continue;
} }
QBackendMetaData backendForTable = metaDataInput.getInstance().getBackendForTable(tableName); QBackendMetaData backendForTable = QContext.getQInstance().getBackendForTable(tableName);
tables.put(tableName, new QFrontendTableMetaData(metaDataInput, backendForTable, table, false, false)); tables.put(tableName, new QFrontendTableMetaData(metaDataInput, backendForTable, table, false, false));
treeNodes.put(tableName, new AppTreeNode(table)); treeNodes.put(tableName, new AppTreeNode(table));
} }
@ -96,7 +97,7 @@ public class MetaDataAction
// map processes to frontend metadata // // map processes to frontend metadata //
//////////////////////////////////////// ////////////////////////////////////////
Map<String, QFrontendProcessMetaData> processes = new LinkedHashMap<>(); Map<String, QFrontendProcessMetaData> processes = new LinkedHashMap<>();
for(Map.Entry<String, QProcessMetaData> entry : metaDataInput.getInstance().getProcesses().entrySet()) for(Map.Entry<String, QProcessMetaData> entry : QContext.getQInstance().getProcesses().entrySet())
{ {
String processName = entry.getKey(); String processName = entry.getKey();
QProcessMetaData process = entry.getValue(); QProcessMetaData process = entry.getValue();
@ -116,7 +117,7 @@ public class MetaDataAction
// map reports to frontend metadata // // map reports to frontend metadata //
////////////////////////////////////// //////////////////////////////////////
Map<String, QFrontendReportMetaData> reports = new LinkedHashMap<>(); Map<String, QFrontendReportMetaData> reports = new LinkedHashMap<>();
for(Map.Entry<String, QReportMetaData> entry : metaDataInput.getInstance().getReports().entrySet()) for(Map.Entry<String, QReportMetaData> entry : QContext.getQInstance().getReports().entrySet())
{ {
String reportName = entry.getKey(); String reportName = entry.getKey();
QReportMetaData report = entry.getValue(); QReportMetaData report = entry.getValue();
@ -136,7 +137,7 @@ public class MetaDataAction
// map widgets to frontend metadata // // map widgets to frontend metadata //
////////////////////////////////////// //////////////////////////////////////
Map<String, QFrontendWidgetMetaData> widgets = new LinkedHashMap<>(); Map<String, QFrontendWidgetMetaData> widgets = new LinkedHashMap<>();
for(Map.Entry<String, QWidgetMetaDataInterface> entry : metaDataInput.getInstance().getWidgets().entrySet()) for(Map.Entry<String, QWidgetMetaDataInterface> entry : QContext.getQInstance().getWidgets().entrySet())
{ {
String widgetName = entry.getKey(); String widgetName = entry.getKey();
QWidgetMetaDataInterface widget = entry.getValue(); QWidgetMetaDataInterface widget = entry.getValue();
@ -154,7 +155,7 @@ public class MetaDataAction
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// sort apps - by sortOrder (integer), then by label // // sort apps - by sortOrder (integer), then by label //
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
List<QAppMetaData> sortedApps = metaDataInput.getInstance().getApps().values().stream() List<QAppMetaData> sortedApps = QContext.getQInstance().getApps().values().stream()
.sorted(Comparator.comparing((QAppMetaData a) -> a.getSortOrder()) .sorted(Comparator.comparing((QAppMetaData a) -> a.getSortOrder())
.thenComparing((QAppMetaData a) -> a.getLabel())) .thenComparing((QAppMetaData a) -> a.getLabel()))
.toList(); .toList();
@ -211,14 +212,14 @@ public class MetaDataAction
//////////////////////////////////// ////////////////////////////////////
// add branding metadata if found // // add branding metadata if found //
//////////////////////////////////// ////////////////////////////////////
if(metaDataInput.getInstance().getBranding() != null) if(QContext.getQInstance().getBranding() != null)
{ {
metaDataOutput.setBranding(metaDataInput.getInstance().getBranding()); metaDataOutput.setBranding(QContext.getQInstance().getBranding());
} }
metaDataOutput.setEnvironmentValues(metaDataInput.getInstance().getEnvironmentValues()); metaDataOutput.setEnvironmentValues(QContext.getQInstance().getEnvironmentValues());
metaDataOutput.setHelpContents(metaDataInput.getInstance().getHelpContent()); metaDataOutput.setHelpContents(QContext.getQInstance().getHelpContent());
// todo post-customization - can do whatever w/ the result if you want? // todo post-customization - can do whatever w/ the result if you want?

View File

@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.actions.metadata;
import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException; import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.model.actions.metadata.ProcessMetaDataInput; import com.kingsrook.qqq.backend.core.model.actions.metadata.ProcessMetaDataInput;
@ -47,7 +48,7 @@ public class ProcessMetaDataAction
// todo pre-customization - just get to modify the request? // todo pre-customization - just get to modify the request?
ProcessMetaDataOutput processMetaDataOutput = new ProcessMetaDataOutput(); ProcessMetaDataOutput processMetaDataOutput = new ProcessMetaDataOutput();
QProcessMetaData process = processMetaDataInput.getInstance().getProcess(processMetaDataInput.getProcessName()); QProcessMetaData process = QContext.getQInstance().getProcess(processMetaDataInput.getProcessName());
if(process == null) if(process == null)
{ {
throw (new QNotFoundException("Process [" + processMetaDataInput.getProcessName() + "] was not found.")); throw (new QNotFoundException("Process [" + processMetaDataInput.getProcessName() + "] was not found."));

View File

@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.actions.metadata;
import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException; import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataInput; import com.kingsrook.qqq.backend.core.model.actions.metadata.TableMetaDataInput;
@ -48,12 +49,12 @@ public class TableMetaDataAction
// todo pre-customization - just get to modify the request? // todo pre-customization - just get to modify the request?
TableMetaDataOutput tableMetaDataOutput = new TableMetaDataOutput(); TableMetaDataOutput tableMetaDataOutput = new TableMetaDataOutput();
QTableMetaData table = tableMetaDataInput.getInstance().getTable(tableMetaDataInput.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(tableMetaDataInput.getTableName());
if(table == null) if(table == null)
{ {
throw (new QNotFoundException("Table [" + tableMetaDataInput.getTableName() + "] was not found.")); throw (new QNotFoundException("Table [" + tableMetaDataInput.getTableName() + "] was not found."));
} }
QBackendMetaData backendForTable = tableMetaDataInput.getInstance().getBackendForTable(table.getName()); QBackendMetaData backendForTable = QContext.getQInstance().getBackendForTable(table.getName());
tableMetaDataOutput.setTable(new QFrontendTableMetaData(tableMetaDataInput, backendForTable, table, true, true)); tableMetaDataOutput.setTable(new QFrontendTableMetaData(tableMetaDataInput, backendForTable, table, true, true));
// todo post-customization - can do whatever w/ the result if you want // todo post-customization - can do whatever w/ the result if you want

View File

@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.actions.processes;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QBadRequestException; import com.kingsrook.qqq.backend.core.exceptions.QBadRequestException;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
@ -54,7 +55,7 @@ public class CancelProcessAction extends RunProcessAction
{ {
ActionHelper.validateSession(runProcessInput); ActionHelper.validateSession(runProcessInput);
QProcessMetaData process = runProcessInput.getInstance().getProcess(runProcessInput.getProcessName()); QProcessMetaData process = QContext.getQInstance().getProcess(runProcessInput.getProcessName());
if(process == null) if(process == null)
{ {
throw new QBadRequestException("Process [" + runProcessInput.getProcessName() + "] is not defined in this instance."); throw new QBadRequestException("Process [" + runProcessInput.getProcessName() + "] is not defined in this instance.");

View File

@ -30,6 +30,7 @@ import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.actions.ActionHelper; import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
@ -64,7 +65,7 @@ public class RunBackendStepAction
{ {
ActionHelper.validateSession(runBackendStepInput); ActionHelper.validateSession(runBackendStepInput);
QProcessMetaData process = runBackendStepInput.getInstance().getProcess(runBackendStepInput.getProcessName()); QProcessMetaData process = QContext.getQInstance().getProcess(runBackendStepInput.getProcessName());
if(process == null) if(process == null)
{ {
throw new QException("Process [" + runBackendStepInput.getProcessName() + "] is not defined in this instance."); throw new QException("Process [" + runBackendStepInput.getProcessName() + "] is not defined in this instance.");

View File

@ -99,7 +99,7 @@ public class RunProcessAction
{ {
ActionHelper.validateSession(runProcessInput); ActionHelper.validateSession(runProcessInput);
QProcessMetaData process = runProcessInput.getInstance().getProcess(runProcessInput.getProcessName()); QProcessMetaData process = QContext.getQInstance().getProcess(runProcessInput.getProcessName());
if(process == null) if(process == null)
{ {
throw new QException("Process [" + runProcessInput.getProcessName() + "] is not defined in this instance."); throw new QException("Process [" + runProcessInput.getProcessName() + "] is not defined in this instance.");

View File

@ -42,6 +42,7 @@ import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
import com.kingsrook.qqq.backend.core.actions.async.AsyncRecordPipeLoop; import com.kingsrook.qqq.backend.core.actions.async.AsyncRecordPipeLoop;
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader; import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
import com.kingsrook.qqq.backend.core.actions.reporting.customizers.DataSourceQueryInputCustomizer; import com.kingsrook.qqq.backend.core.actions.reporting.customizers.DataSourceQueryInputCustomizer;
import com.kingsrook.qqq.backend.core.actions.reporting.customizers.ReportCustomRecordSourceInterface;
import com.kingsrook.qqq.backend.core.actions.reporting.customizers.ReportViewCustomizer; import com.kingsrook.qqq.backend.core.actions.reporting.customizers.ReportViewCustomizer;
import com.kingsrook.qqq.backend.core.actions.tables.CountAction; import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
@ -302,10 +303,19 @@ public class GenerateReportAction extends AbstractQActionFunction<ReportInput, R
JoinsContext joinsContext = null; JoinsContext joinsContext = null;
if(dataSource != null) if(dataSource != null)
{ {
///////////////////////////////////////////////////////////////////////////////////////
// count records, if applicable, from the data source - for populating into the //
// countByDataSource map, as well as for checking if too many rows (e.g., for excel) //
///////////////////////////////////////////////////////////////////////////////////////
countDataSourceRecords(reportInput, dataSource, reportFormat);
///////////////////////////////////////////////////////////////////////////////////////////
// if there's a source table, set up a joins context, to use below for looking up fields //
///////////////////////////////////////////////////////////////////////////////////////////
if(StringUtils.hasContent(dataSource.getSourceTable())) if(StringUtils.hasContent(dataSource.getSourceTable()))
{ {
joinsContext = new JoinsContext(QContext.getQInstance(), dataSource.getSourceTable(), cloneDataSourceQueryJoins(dataSource), dataSource.getQueryFilter() == null ? null : dataSource.getQueryFilter().clone()); QQueryFilter queryFilter = dataSource.getQueryFilter() == null ? new QQueryFilter() : dataSource.getQueryFilter().clone();
countDataSourceRecords(reportInput, dataSource, reportFormat); joinsContext = new JoinsContext(QContext.getQInstance(), dataSource.getSourceTable(), dataSource.getQueryJoins(), queryFilter);
} }
} }
@ -329,6 +339,7 @@ public class GenerateReportAction extends AbstractQActionFunction<ReportInput, R
field.setName(column.getName()); field.setName(column.getName());
if(StringUtils.hasContent(column.getLabel())) if(StringUtils.hasContent(column.getLabel()))
{ {
field.setLabel(column.getLabel()); field.setLabel(column.getLabel());
} }
fields.add(field); fields.add(field);
@ -345,6 +356,13 @@ public class GenerateReportAction extends AbstractQActionFunction<ReportInput, R
** **
*******************************************************************************/ *******************************************************************************/
private void countDataSourceRecords(ReportInput reportInput, QReportDataSource dataSource, ReportFormat reportFormat) throws QException private void countDataSourceRecords(ReportInput reportInput, QReportDataSource dataSource, ReportFormat reportFormat) throws QException
{
Integer count = null;
if(dataSource.getCustomRecordSource() != null)
{
// todo - add `count` method to interface?
}
else if(StringUtils.hasContent(dataSource.getSourceTable()))
{ {
QQueryFilter queryFilter = dataSource.getQueryFilter() == null ? new QQueryFilter() : dataSource.getQueryFilter().clone(); QQueryFilter queryFilter = dataSource.getQueryFilter() == null ? new QQueryFilter() : dataSource.getQueryFilter().clone();
setInputValuesInQueryFilter(reportInput, queryFilter); setInputValuesInQueryFilter(reportInput, queryFilter);
@ -355,14 +373,17 @@ public class GenerateReportAction extends AbstractQActionFunction<ReportInput, R
countInput.setQueryJoins(cloneDataSourceQueryJoins(dataSource)); countInput.setQueryJoins(cloneDataSourceQueryJoins(dataSource));
CountOutput countOutput = new CountAction().execute(countInput); CountOutput countOutput = new CountAction().execute(countInput);
if(countOutput.getCount() != null) count = countOutput.getCount();
{ }
countByDataSource.put(dataSource.getName(), countOutput.getCount());
if(reportFormat.getMaxRows() != null && countOutput.getCount() > reportFormat.getMaxRows()) if(count != null)
{
countByDataSource.put(dataSource.getName(), count);
if(reportFormat.getMaxRows() != null && count > reportFormat.getMaxRows())
{ {
throw (new QUserFacingException("The requested report would include more rows (" throw (new QUserFacingException("The requested report would include more rows ("
+ String.format("%,d", countOutput.getCount()) + ") than the maximum allowed (" + String.format("%,d", count) + ") than the maximum allowed ("
+ String.format("%,d", reportFormat.getMaxRows()) + ") for the selected file format (" + reportFormat + ").")); + String.format("%,d", reportFormat.getMaxRows()) + ") for the selected file format (" + reportFormat + ")."));
} }
} }
@ -423,13 +444,19 @@ public class GenerateReportAction extends AbstractQActionFunction<ReportInput, R
String tableLabel = ObjectUtils.tryElse(() -> QContext.getQInstance().getTable(dataSource.getSourceTable()).getLabel(), Objects.requireNonNullElse(dataSource.getSourceTable(), "")); String tableLabel = ObjectUtils.tryElse(() -> QContext.getQInstance().getTable(dataSource.getSourceTable()).getLabel(), Objects.requireNonNullElse(dataSource.getSourceTable(), ""));
AtomicInteger consumedCount = new AtomicInteger(0); AtomicInteger consumedCount = new AtomicInteger(0);
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////
// run a record pipe loop, over the query for this data source // // run a record pipe loop, over the query (or other data-supplier/source) for this data source //
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////
RecordPipe recordPipe = new BufferedRecordPipe(1000); RecordPipe recordPipe = new BufferedRecordPipe(1000);
new AsyncRecordPipeLoop().run("Report[" + reportInput.getReportName() + "]", null, recordPipe, (callback) -> new AsyncRecordPipeLoop().run("Report[" + reportInput.getReportName() + "]", null, recordPipe, (callback) ->
{ {
if(dataSource.getSourceTable() != null) if(dataSource.getCustomRecordSource() != null)
{
ReportCustomRecordSourceInterface recordSource = QCodeLoader.getAdHoc(ReportCustomRecordSourceInterface.class, dataSource.getCustomRecordSource());
recordSource.execute(reportInput, dataSource, recordPipe);
return (true);
}
else if(dataSource.getSourceTable() != null)
{ {
QQueryFilter queryFilter = dataSource.getQueryFilter() == null ? new QQueryFilter() : dataSource.getQueryFilter().clone(); QQueryFilter queryFilter = dataSource.getQueryFilter() == null ? new QQueryFilter() : dataSource.getQueryFilter().clone();
setInputValuesInQueryFilter(reportInput, queryFilter); setInputValuesInQueryFilter(reportInput, queryFilter);

View File

@ -0,0 +1,43 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.actions.reporting.customizers;
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportDataSource;
/*******************************************************************************
** Interface to be implemented to do a custom source of data for a report
** (instead of just a query against a table).
*******************************************************************************/
public interface ReportCustomRecordSourceInterface
{
/***************************************************************************
** Given the report input, put records into the pipe, for the report.
***************************************************************************/
void execute(ReportInput reportInput, QReportDataSource reportDataSource, RecordPipe recordPipe) throws QException;
}

View File

@ -124,7 +124,7 @@ public class ExcelFastexcelExportStreamer implements ExportStreamerInterface
if(workbook == null) if(workbook == null)
{ {
String appName = ObjectUtils.tryAndRequireNonNullElse(() -> QContext.getQInstance().getBranding().getAppName(), "QQQ"); String appName = ObjectUtils.tryAndRequireNonNullElse(() -> QContext.getQInstance().getBranding().getAppName(), "QQQ");
QInstance instance = exportInput.getInstance(); QInstance instance = QContext.getQInstance();
if(instance != null && instance.getBranding() != null && instance.getBranding().getCompanyName() != null) if(instance != null && instance.getBranding() != null && instance.getBranding().getCompanyName() != null)
{ {
appName = instance.getBranding().getCompanyName(); appName = instance.getBranding().getCompanyName();

View File

@ -128,6 +128,7 @@ public class ExcelPoiBasedStreamingExportStreamer implements ExportStreamerInter
private Map<String, List<QFieldMetaData>> fieldsPerView = new HashMap<>(); private Map<String, List<QFieldMetaData>> fieldsPerView = new HashMap<>();
private Map<String, Integer> rowsPerView = new HashMap<>(); private Map<String, Integer> rowsPerView = new HashMap<>();
private Map<String, String> labelViewsByName = new HashMap<>(); private Map<String, String> labelViewsByName = new HashMap<>();
private Map<String, String> sheetReferenceByViewName = new HashMap<>();
@ -180,6 +181,7 @@ public class ExcelPoiBasedStreamingExportStreamer implements ExportStreamerInter
String sheetReference = sheet.getPackagePart().getPartName().getName().substring(1); String sheetReference = sheet.getPackagePart().getPartName().getName().substring(1);
sheetMapByExcelReference.put(sheetReference, sheet); sheetMapByExcelReference.put(sheetReference, sheet);
sheetMapByViewName.put(view.getName(), sheet); sheetMapByViewName.put(view.getName(), sheet);
sheetReferenceByViewName.put(view.getName(), sheetReference);
sheetCounter++; sheetCounter++;
} }
@ -446,7 +448,7 @@ public class ExcelPoiBasedStreamingExportStreamer implements ExportStreamerInter
// - with a new output stream writer // // - with a new output stream writer //
// - and with a SpreadsheetWriter // // - and with a SpreadsheetWriter //
////////////////////////////////////////// //////////////////////////////////////////
zipOutputStream.putNextEntry(new ZipEntry("xl/worksheets/sheet" + this.sheetIndex++ + ".xml")); zipOutputStream.putNextEntry(new ZipEntry(sheetReferenceByViewName.get(view.getName())));
activeSheetWriter = new OutputStreamWriter(zipOutputStream); activeSheetWriter = new OutputStreamWriter(zipOutputStream);
sheetWriter = new StreamedSheetWriter(activeSheetWriter); sheetWriter = new StreamedSheetWriter(activeSheetWriter);

View File

@ -161,7 +161,7 @@ public class StreamedSheetWriter
} }
} }
Map<String, Integer> m = new HashMap(); Map<String, Integer> m = new HashMap<>();
m.computeIfAbsent("s", (s) -> 3); m.computeIfAbsent("s", (s) -> 3);
value = rs.toString(); value = rs.toString();

View File

@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.actions.scripts;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.BuildScriptLogAndScriptLogLineExecutionLogger; import com.kingsrook.qqq.backend.core.actions.scripts.logging.BuildScriptLogAndScriptLogLineExecutionLogger;
@ -97,7 +98,7 @@ public class RecordScriptTestInterface implements TestScriptActionInterface
} }
QueryOutput queryOutput = new QueryAction().execute(new QueryInput(tableName) QueryOutput queryOutput = new QueryAction().execute(new QueryInput(tableName)
.withFilter(new QQueryFilter(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, recordPrimaryKeyList.split(",")))) .withFilter(new QQueryFilter(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, Arrays.stream(recordPrimaryKeyList.split(",")).toList())))
.withIncludeAssociations(true)); .withIncludeAssociations(true));
if(CollectionUtils.nullSafeIsEmpty(queryOutput.getRecords())) if(CollectionUtils.nullSafeIsEmpty(queryOutput.getRecords()))
{ {

View File

@ -154,8 +154,9 @@ public class RunAdHocRecordScriptAction
Method qRecordListToApiRecordList = apiScriptUtilsClass.getMethod("qRecordListToApiRecordList", List.class, String.class, String.class, String.class); Method qRecordListToApiRecordList = apiScriptUtilsClass.getMethod("qRecordListToApiRecordList", List.class, String.class, String.class, String.class);
Object apiRecordList = qRecordListToApiRecordList.invoke(null, input.getRecordList(), input.getTableName(), scriptRevision.getApiName(), scriptRevision.getApiVersion()); Object apiRecordList = qRecordListToApiRecordList.invoke(null, input.getRecordList(), input.getTableName(), scriptRevision.getApiName(), scriptRevision.getApiVersion());
// noinspection unchecked @SuppressWarnings("unchecked")
return (ArrayList<? extends Serializable>) apiRecordList; ArrayList<? extends Serializable> rs = (ArrayList<? extends Serializable>) apiRecordList;
return rs;
} }
catch(ClassNotFoundException e) catch(ClassNotFoundException e)
{ {

View File

@ -352,7 +352,7 @@ public class GetAction
{ {
if(qPossibleValueTranslator == null) if(qPossibleValueTranslator == null)
{ {
qPossibleValueTranslator = new QPossibleValueTranslator(getInput.getInstance(), getInput.getSession()); qPossibleValueTranslator = new QPossibleValueTranslator(QContext.getQInstance(), QContext.getQSession());
} }
qPossibleValueTranslator.translatePossibleValuesInRecords(getInput.getTable(), List.of(returnRecord)); qPossibleValueTranslator.translatePossibleValuesInRecords(getInput.getTable(), List.of(returnRecord));
} }

View File

@ -227,6 +227,11 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
*******************************************************************************/ *******************************************************************************/
public void performValidations(InsertInput insertInput, boolean isPreview) throws QException public void performValidations(InsertInput insertInput, boolean isPreview) throws QException
{ {
if(CollectionUtils.nullSafeIsEmpty(insertInput.getRecords()))
{
return;
}
QTableMetaData table = insertInput.getTable(); QTableMetaData table = insertInput.getTable();
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
@ -241,7 +246,7 @@ public class InsertAction extends AbstractQActionFunction<InsertInput, InsertOut
setDefaultValuesInRecords(table, insertInput.getRecords()); setDefaultValuesInRecords(table, insertInput.getRecords());
ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.INSERT, insertInput.getInstance(), table, insertInput.getRecords(), null); ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.INSERT, QContext.getQInstance(), table, insertInput.getRecords(), null);
runPreInsertCustomizerIfItIsTime(insertInput, isPreview, preInsertCustomizer, AbstractPreInsertCustomizer.WhenToRun.BEFORE_UNIQUE_KEY_CHECKS); runPreInsertCustomizerIfItIsTime(insertInput, isPreview, preInsertCustomizer, AbstractPreInsertCustomizer.WhenToRun.BEFORE_UNIQUE_KEY_CHECKS);
setErrorsIfUniqueKeyErrors(insertInput, table); setErrorsIfUniqueKeyErrors(insertInput, table);

View File

@ -26,6 +26,7 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -50,6 +51,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperat
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
@ -64,6 +66,7 @@ import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.ListingHash; import com.kingsrook.qqq.backend.core.utils.ListingHash;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.ValueUtils; import com.kingsrook.qqq.backend.core.utils.ValueUtils;
@ -101,6 +104,8 @@ public class QueryAction
throw (new QException("A table named [" + queryInput.getTableName() + "] was not found in the active QInstance")); throw (new QException("A table named [" + queryInput.getTableName() + "] was not found in the active QInstance"));
} }
validateFieldNamesToInclude(queryInput);
QBackendMetaData backend = queryInput.getBackend(); QBackendMetaData backend = queryInput.getBackend();
postQueryRecordCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.POST_QUERY_RECORD.getRole()); postQueryRecordCustomizer = QCodeLoader.getTableCustomizer(table, TableCustomizers.POST_QUERY_RECORD.getRole());
this.queryInput = queryInput; this.queryInput = queryInput;
@ -158,6 +163,109 @@ public class QueryAction
/***************************************************************************
** if QueryInput contains a set of FieldNamesToInclude, then validate that
** those are known field names in the table being queried, or a selected
** queryJoin.
***************************************************************************/
static void validateFieldNamesToInclude(QueryInput queryInput) throws QException
{
Set<String> fieldNamesToInclude = queryInput.getFieldNamesToInclude();
if(fieldNamesToInclude == null)
{
////////////////////////////////
// null set means select all. //
////////////////////////////////
return;
}
if(fieldNamesToInclude.isEmpty())
{
/////////////////////////////////////
// empty set, however, is an error //
/////////////////////////////////////
throw (new QException("An empty set of fieldNamesToInclude was given as queryInput, which is not allowed."));
}
List<String> unrecognizedFieldNames = new ArrayList<>();
Map<String, QTableMetaData> selectedQueryJoins = null;
for(String fieldName : fieldNamesToInclude)
{
if(fieldName.contains("."))
{
////////////////////////////////////////////////
// handle names with dots - fields from joins //
////////////////////////////////////////////////
String[] parts = fieldName.split("\\.");
if(parts.length != 2)
{
unrecognizedFieldNames.add(fieldName);
}
else
{
String tableOrAlias = parts[0];
String fieldNamePart = parts[1];
////////////////////////////////////////////
// build map of queryJoins being selected //
////////////////////////////////////////////
if(selectedQueryJoins == null)
{
selectedQueryJoins = new HashMap<>();
for(QueryJoin queryJoin : CollectionUtils.nonNullList(queryInput.getQueryJoins()))
{
if(queryJoin.getSelect())
{
String joinTableOrAlias = queryJoin.getJoinTableOrItsAlias();
QTableMetaData joinTable = QContext.getQInstance().getTable(queryJoin.getJoinTable());
if(joinTable != null)
{
selectedQueryJoins.put(joinTableOrAlias, joinTable);
}
}
}
}
if(!selectedQueryJoins.containsKey(tableOrAlias))
{
///////////////////////////////////////////
// unrecognized tableOrAlias is an error //
///////////////////////////////////////////
unrecognizedFieldNames.add(fieldName);
}
else
{
QTableMetaData joinTable = selectedQueryJoins.get(tableOrAlias);
if(!joinTable.getFields().containsKey(fieldNamePart))
{
//////////////////////////////////////////////////////////
// unrecognized field within the join table is an error //
//////////////////////////////////////////////////////////
unrecognizedFieldNames.add(fieldName);
}
}
}
}
else
{
///////////////////////////////////////////////////////////////////////
// non-join fields - just ensure field name is in table's fields map //
///////////////////////////////////////////////////////////////////////
if(!queryInput.getTable().getFields().containsKey(fieldName))
{
unrecognizedFieldNames.add(fieldName);
}
}
}
if(!unrecognizedFieldNames.isEmpty())
{
throw (new QException("QueryInput contained " + unrecognizedFieldNames.size() + " unrecognized field name" + StringUtils.plural(unrecognizedFieldNames) + ": " + StringUtils.join(",", unrecognizedFieldNames)));
}
}
/******************************************************************************* /*******************************************************************************
** shorthand way to call for the most common use-case, when you just want the ** shorthand way to call for the most common use-case, when you just want the
** records to be returned, and you just want to pass in a table name and filter. ** records to be returned, and you just want to pass in a table name and filter.
@ -297,7 +405,7 @@ public class QueryAction
{ {
if(qPossibleValueTranslator == null) if(qPossibleValueTranslator == null)
{ {
qPossibleValueTranslator = new QPossibleValueTranslator(queryInput.getInstance(), queryInput.getSession()); qPossibleValueTranslator = new QPossibleValueTranslator(QContext.getQInstance(), QContext.getQSession());
} }
qPossibleValueTranslator.translatePossibleValuesInRecords(queryInput.getTable(), records, queryInput.getQueryJoins(), queryInput.getFieldsToTranslatePossibleValues()); qPossibleValueTranslator.translatePossibleValuesInRecords(queryInput.getTable(), records, queryInput.getQueryJoins(), queryInput.getFieldsToTranslatePossibleValues());
} }

View File

@ -252,7 +252,7 @@ public class UpdateAction
behaviorsToOmit = Set.of(DynamicDefaultValueBehavior.MODIFY_DATE); behaviorsToOmit = Set.of(DynamicDefaultValueBehavior.MODIFY_DATE);
} }
ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.UPDATE, updateInput.getInstance(), table, updateInput.getRecords(), behaviorsToOmit); ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.UPDATE, QContext.getQInstance(), table, updateInput.getRecords(), behaviorsToOmit);
validatePrimaryKeysAreGiven(updateInput); validatePrimaryKeysAreGiven(updateInput);
if(oldRecordList.isPresent()) if(oldRecordList.isPresent())

View File

@ -68,7 +68,7 @@ public class QValueFormatter
*******************************************************************************/ *******************************************************************************/
public static String formatValue(QFieldMetaData field, Serializable value) public static String formatValue(QFieldMetaData field, Serializable value)
{ {
return (formatValue(field.getDisplayFormat(), field.getName(), value)); return (formatValue(field.getDisplayFormat(), field.getType(), field.getName(), value));
} }
@ -78,7 +78,7 @@ public class QValueFormatter
*******************************************************************************/ *******************************************************************************/
public static String formatValue(String displayFormat, Serializable value) public static String formatValue(String displayFormat, Serializable value)
{ {
return (formatValue(displayFormat, "", value)); return (formatValue(displayFormat, null, "", value));
} }
@ -87,7 +87,7 @@ public class QValueFormatter
** For a display format string, an optional fieldName (only used for logging), ** For a display format string, an optional fieldName (only used for logging),
** and a value, apply the format. ** and a value, apply the format.
*******************************************************************************/ *******************************************************************************/
private static String formatValue(String displayFormat, String fieldName, Serializable value) private static String formatValue(String displayFormat, QFieldType fieldType, String fieldName, Serializable value)
{ {
////////////////////////////////// //////////////////////////////////
// null values get null results // // null values get null results //
@ -107,6 +107,11 @@ public class QValueFormatter
return formatBoolean(b); return formatBoolean(b);
} }
if(QFieldType.BOOLEAN.equals(fieldType))
{
return formatBoolean(ValueUtils.getValueAsBoolean(value));
}
if(value instanceof LocalTime lt) if(value instanceof LocalTime lt)
{ {
return formatLocalTime(lt); return formatLocalTime(lt);
@ -404,6 +409,7 @@ public class QValueFormatter
} }
/******************************************************************************* /*******************************************************************************
** For a single record, set its display values - where caller (meant to stay private) ** For a single record, set its display values - where caller (meant to stay private)
** can specify if they've already done fieldBehaviors (to avoid re-doing). ** can specify if they've already done fieldBehaviors (to avoid re-doing).
@ -563,6 +569,7 @@ public class QValueFormatter
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// heavy fields that weren't fetched - they should have a backend-detail specifying their length (or null if null) // // heavy fields that weren't fetched - they should have a backend-detail specifying their length (or null if null) //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked")
Map<String, Serializable> heavyFieldLengths = (Map<String, Serializable>) record.getBackendDetail(QRecord.BACKEND_DETAILS_TYPE_HEAVY_FIELD_LENGTHS); Map<String, Serializable> heavyFieldLengths = (Map<String, Serializable>) record.getBackendDetail(QRecord.BACKEND_DETAILS_TYPE_HEAVY_FIELD_LENGTHS);
if(heavyFieldLengths != null) if(heavyFieldLengths != null)
{ {

View File

@ -30,6 +30,7 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader; import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
@ -69,14 +70,14 @@ public class SearchPossibleValueSourceAction
*******************************************************************************/ *******************************************************************************/
public SearchPossibleValueSourceOutput execute(SearchPossibleValueSourceInput input) throws QException public SearchPossibleValueSourceOutput execute(SearchPossibleValueSourceInput input) throws QException
{ {
QInstance qInstance = input.getInstance(); QInstance qInstance = QContext.getQInstance();
QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(input.getPossibleValueSourceName()); QPossibleValueSource possibleValueSource = qInstance.getPossibleValueSource(input.getPossibleValueSourceName());
if(possibleValueSource == null) if(possibleValueSource == null)
{ {
throw new QException("Missing possible value source named [" + input.getPossibleValueSourceName() + "]"); throw new QException("Missing possible value source named [" + input.getPossibleValueSourceName() + "]");
} }
possibleValueTranslator = new QPossibleValueTranslator(input.getInstance(), input.getSession()); possibleValueTranslator = new QPossibleValueTranslator(QContext.getQInstance(), QContext.getQSession());
SearchPossibleValueSourceOutput output = null; SearchPossibleValueSourceOutput output = null;
if(possibleValueSource.getType().equals(QPossibleValueSourceType.ENUM)) if(possibleValueSource.getType().equals(QPossibleValueSourceType.ENUM))
{ {
@ -199,7 +200,7 @@ public class SearchPossibleValueSourceAction
QueryInput queryInput = new QueryInput(); QueryInput queryInput = new QueryInput();
queryInput.setTableName(possibleValueSource.getTableName()); queryInput.setTableName(possibleValueSource.getTableName());
QTableMetaData table = input.getInstance().getTable(possibleValueSource.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(possibleValueSource.getTableName());
QQueryFilter queryFilter = new QQueryFilter(); QQueryFilter queryFilter = new QQueryFilter();
queryFilter.setBooleanOperator(QQueryFilter.BooleanOperator.OR); queryFilter.setBooleanOperator(QQueryFilter.BooleanOperator.OR);
@ -299,6 +300,7 @@ public class SearchPossibleValueSourceAction
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings({ "rawtypes", "unchecked" })
private SearchPossibleValueSourceOutput searchPossibleValueCustom(SearchPossibleValueSourceInput input, QPossibleValueSource possibleValueSource) private SearchPossibleValueSourceOutput searchPossibleValueCustom(SearchPossibleValueSourceInput input, QPossibleValueSource possibleValueSource)
{ {
try try

View File

@ -22,8 +22,8 @@
package com.kingsrook.qqq.backend.core.exceptions; package com.kingsrook.qqq.backend.core.exceptions;
import java.util.Arrays;
import java.util.List; import java.util.List;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils;
@ -55,12 +55,11 @@ public class QInstanceValidationException extends QException
*******************************************************************************/ *******************************************************************************/
public QInstanceValidationException(List<String> reasons) public QInstanceValidationException(List<String> reasons)
{ {
super( super((CollectionUtils.nullSafeHasContents(reasons))
(reasons != null && reasons.size() > 0) ? "Instance validation failed for the following reasons:\n - " + StringUtils.join("\n - ", reasons) + "\n(" + reasons.size() + " Total reason" + StringUtils.plural(reasons) + ")"
? "Instance validation failed for the following reasons:\n - " + StringUtils.join("\n - ", reasons)
: "Validation failed, but no reasons were provided"); : "Validation failed, but no reasons were provided");
if(reasons != null && reasons.size() > 0) if(CollectionUtils.nullSafeHasContents(reasons))
{ {
this.reasons = reasons; this.reasons = reasons;
} }
@ -68,25 +67,6 @@ public class QInstanceValidationException extends QException
/*******************************************************************************
** Constructor of an array/varargs of reasons. They feed into the core exception message.
**
*******************************************************************************/
public QInstanceValidationException(String... reasons)
{
super(
(reasons != null && reasons.length > 0)
? "Instance validation failed for the following reasons: " + StringUtils.joinWithCommasAndAnd(Arrays.stream(reasons).toList())
: "Validation failed, but no reasons were provided");
if(reasons != null && reasons.length > 0)
{
this.reasons = Arrays.stream(reasons).toList();
}
}
/******************************************************************************* /*******************************************************************************
** Constructor of message & cause - does not populate reasons! ** Constructor of message & cause - does not populate reasons!
** **

View File

@ -44,6 +44,7 @@ import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer; import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph; import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.reporting.customizers.ReportCustomRecordSourceInterface;
import com.kingsrook.qqq.backend.core.actions.scripts.TestScriptActionInterface; import com.kingsrook.qqq.backend.core.actions.scripts.TestScriptActionInterface;
import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider; import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider;
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException; import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
@ -922,7 +923,7 @@ public class QInstanceValidator
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
private <T extends FieldBehavior<T>> void validateTableField(QInstance qInstance, String tableName, String fieldName, QTableMetaData table, QFieldMetaData field) private void validateTableField(QInstance qInstance, String tableName, String fieldName, QTableMetaData table, QFieldMetaData field)
{ {
assertCondition(Objects.equals(fieldName, field.getName()), assertCondition(Objects.equals(fieldName, field.getName()),
"Inconsistent naming in table " + tableName + " for field " + fieldName + "/" + field.getName() + "."); "Inconsistent naming in table " + tableName + " for field " + fieldName + "/" + field.getName() + ".");
@ -944,12 +945,13 @@ public class QInstanceValidator
assertCondition(field.getMaxLength() != null, prefix + "specifies a ValueTooLongBehavior, but not a maxLength."); assertCondition(field.getMaxLength() != null, prefix + "specifies a ValueTooLongBehavior, but not a maxLength.");
} }
Set<Class<FieldBehavior<T>>> usedFieldBehaviorTypes = new HashSet<>(); Set<Class<FieldBehavior<?>>> usedFieldBehaviorTypes = new HashSet<>();
if(field.getBehaviors() != null) if(field.getBehaviors() != null)
{ {
for(FieldBehavior<?> fieldBehavior : field.getBehaviors()) for(FieldBehavior<?> fieldBehavior : field.getBehaviors())
{ {
Class<FieldBehavior<T>> behaviorClass = (Class<FieldBehavior<T>>) fieldBehavior.getClass(); @SuppressWarnings("unchecked")
Class<FieldBehavior<?>> behaviorClass = (Class<FieldBehavior<?>>) fieldBehavior.getClass();
errors.addAll(fieldBehavior.validateBehaviorConfiguration(table, field)); errors.addAll(fieldBehavior.validateBehaviorConfiguration(table, field));
@ -1659,9 +1661,12 @@ public class QInstanceValidator
String dataSourceErrorPrefix = "Report " + reportName + " data source " + dataSource.getName() + " "; String dataSourceErrorPrefix = "Report " + reportName + " data source " + dataSource.getName() + " ";
boolean hasASource = false;
if(StringUtils.hasContent(dataSource.getSourceTable())) if(StringUtils.hasContent(dataSource.getSourceTable()))
{ {
assertCondition(dataSource.getStaticDataSupplier() == null, dataSourceErrorPrefix + "has both a sourceTable and a staticDataSupplier (exactly 1 is required)."); hasASource = true;
assertCondition(dataSource.getStaticDataSupplier() == null, dataSourceErrorPrefix + "has both a sourceTable and a staticDataSupplier (not compatible together).");
if(assertCondition(qInstance.getTable(dataSource.getSourceTable()) != null, dataSourceErrorPrefix + "source table " + dataSource.getSourceTable() + " is not a table in this instance.")) if(assertCondition(qInstance.getTable(dataSource.getSourceTable()) != null, dataSourceErrorPrefix + "source table " + dataSource.getSourceTable() + " is not a table in this instance."))
{ {
if(dataSource.getQueryFilter() != null) if(dataSource.getQueryFilter() != null)
@ -1670,14 +1675,21 @@ public class QInstanceValidator
} }
} }
} }
else if(dataSource.getStaticDataSupplier() != null)
if(dataSource.getStaticDataSupplier() != null)
{ {
assertCondition(dataSource.getCustomRecordSource() == null, dataSourceErrorPrefix + "has both a staticDataSupplier and a customRecordSource (not compatible together).");
hasASource = true;
validateSimpleCodeReference(dataSourceErrorPrefix, dataSource.getStaticDataSupplier(), Supplier.class); validateSimpleCodeReference(dataSourceErrorPrefix, dataSource.getStaticDataSupplier(), Supplier.class);
} }
else
if(dataSource.getCustomRecordSource() != null)
{ {
errors.add(dataSourceErrorPrefix + "does not have a sourceTable or a staticDataSupplier (exactly 1 is required)."); hasASource = true;
validateSimpleCodeReference(dataSourceErrorPrefix, dataSource.getCustomRecordSource(), ReportCustomRecordSourceInterface.class);
} }
assertCondition(hasASource, dataSourceErrorPrefix + "does not have a sourceTable, customRecordSource, or a staticDataSupplier.");
} }
} }

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.instances;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.AWSStaticCredentialsProvider;
@ -113,7 +114,7 @@ public class SecretsManagerUtils
dotEnv.renameTo(new File(".env.backup-" + System.currentTimeMillis())); dotEnv.renameTo(new File(".env.backup-" + System.currentTimeMillis()));
} }
FileUtils.writeStringToFile(dotEnv, fullEnv.toString()); FileUtils.writeStringToFile(dotEnv, fullEnv.toString(), StandardCharsets.UTF_8);
} }
else else
{ {

View File

@ -32,7 +32,6 @@ import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator; import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
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.authentication.QAuthenticationMetaData;
import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.session.QSession;
@ -93,17 +92,6 @@ public class AbstractActionInput
/*******************************************************************************
**
*******************************************************************************/
@JsonIgnore
public QAuthenticationMetaData getAuthenticationMetaData()
{
return (getInstance().getAuthentication());
}
/******************************************************************************* /*******************************************************************************
** Getter for instance ** Getter for instance
** **

View File

@ -152,5 +152,8 @@ public class AuditDetailAccumulator implements Serializable
} }
/***************************************************************************
**
***************************************************************************/
private record TableNameAndPrimaryKey(String tableName, Serializable primaryKey) {} private record TableNameAndPrimaryKey(String tableName, Serializable primaryKey) {}
} }

View File

@ -59,6 +59,30 @@ public class AggregateInput extends AbstractTableActionInput
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public AggregateInput(String tableName)
{
this();
setTableName(tableName);
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public AggregateInput withTableName(String tableName)
{
super.withTableName(tableName);
return (this);
}
/******************************************************************************* /*******************************************************************************
** Getter for filter ** Getter for filter
** **

View File

@ -66,6 +66,14 @@ public class QueryInput extends AbstractTableActionInput implements QueryOrGetIn
private List<QueryJoin> queryJoins = null; private List<QueryJoin> queryJoins = null;
private boolean selectDistinct = false; private boolean selectDistinct = false;
/////////////////////////////////////////////////////////////////////////////
// if this set is null, then the default (all fields) should be included //
// if it's an empty set, that should throw an error //
// or if there are any fields in it that aren't valid fields on the table, //
// or in a selected queryJoin. //
/////////////////////////////////////////////////////////////////////////////
private Set<String> fieldNamesToInclude;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if you say you want to includeAssociations, you can limit which ones by passing them in associationNamesToInclude. // // if you say you want to includeAssociations, you can limit which ones by passing them in associationNamesToInclude. //
// if you leave it null, you get all associations defined on the table. if you pass it as empty, you get none. // // if you leave it null, you get all associations defined on the table. if you pass it as empty, you get none. //
@ -686,4 +694,35 @@ public class QueryInput extends AbstractTableActionInput implements QueryOrGetIn
return (queryHints.contains(queryHint)); return (queryHints.contains(queryHint));
} }
/*******************************************************************************
** Getter for fieldNamesToInclude
*******************************************************************************/
public Set<String> getFieldNamesToInclude()
{
return (this.fieldNamesToInclude);
}
/*******************************************************************************
** Setter for fieldNamesToInclude
*******************************************************************************/
public void setFieldNamesToInclude(Set<String> fieldNamesToInclude)
{
this.fieldNamesToInclude = fieldNamesToInclude;
}
/*******************************************************************************
** Fluent setter for fieldNamesToInclude
*******************************************************************************/
public QueryInput withFieldNamesToInclude(Set<String> fieldNamesToInclude)
{
this.fieldNamesToInclude = fieldNamesToInclude;
return (this);
}
} }

View File

@ -40,11 +40,14 @@ public abstract class AbstractFilterExpression<T extends Serializable> implement
/******************************************************************************* /*******************************************************************************
** Evaluate the expression, given a map of input values.
** **
** By default, this will defer to the evaluate(void) method - but, a subclass
** (e.g., FilterVariableExpression) may react differently.
*******************************************************************************/ *******************************************************************************/
public T evaluateInputValues(Map<String, Serializable> inputValues) throws QException public T evaluateInputValues(Map<String, Serializable> inputValues) throws QException
{ {
return (T) this; return evaluate();
} }

View File

@ -42,6 +42,9 @@ public class NowWithOffset extends AbstractFilterExpression<Instant>
/***************************************************************************
**
***************************************************************************/
public enum Operator public enum Operator
{PLUS, MINUS} {PLUS, MINUS}

View File

@ -43,6 +43,9 @@ public class ThisOrLastPeriod extends AbstractFilterExpression<Instant>
/***************************************************************************
**
***************************************************************************/
public enum Operator public enum Operator
{THIS, LAST} {THIS, LAST}

View File

@ -79,6 +79,7 @@ public class QFilterCriteriaDeserializer extends StdDeserializer<QFilterCriteria
///////////////////////////////// /////////////////////////////////
// get values out of json node // // get values out of json node //
///////////////////////////////// /////////////////////////////////
@SuppressWarnings("unchecked")
List<Serializable> values = objectMapper.treeToValue(node.get("values"), List.class); List<Serializable> values = objectMapper.treeToValue(node.get("values"), List.class);
String fieldName = objectMapper.treeToValue(node.get("fieldName"), String.class); String fieldName = objectMapper.treeToValue(node.get("fieldName"), String.class);
QCriteriaOperator operator = objectMapper.treeToValue(node.get("operator"), QCriteriaOperator.class); QCriteriaOperator operator = objectMapper.treeToValue(node.get("operator"), QCriteriaOperator.class);

View File

@ -28,6 +28,9 @@ package com.kingsrook.qqq.backend.core.model.dashboard.widgets;
*******************************************************************************/ *******************************************************************************/
public class AlertData extends QWidgetData public class AlertData extends QWidgetData
{ {
/***************************************************************************
**
***************************************************************************/
public enum AlertType public enum AlertType
{ {
ERROR, ERROR,

View File

@ -40,9 +40,10 @@ public class CompositeWidgetData extends AbstractBlockWidgetData<CompositeWidget
{ {
private List<AbstractBlockWidgetData<?, ?, ?, ?>> blocks = new ArrayList<>(); private List<AbstractBlockWidgetData<?, ?, ?, ?>> blocks = new ArrayList<>();
private Map<String, Serializable> styleOverrides = new HashMap<>();
private Layout layout; private Layout layout;
private Map<String, Serializable> styleOverrides = new HashMap<>();
private String overlayHtml;
private Map<String, Serializable> overlayStyleOverrides = new HashMap<>();
@ -218,4 +219,91 @@ public class CompositeWidgetData extends AbstractBlockWidgetData<CompositeWidget
return (this); return (this);
} }
/*******************************************************************************
** Getter for overlayHtml
*******************************************************************************/
public String getOverlayHtml()
{
return (this.overlayHtml);
}
/*******************************************************************************
** Setter for overlayHtml
*******************************************************************************/
public void setOverlayHtml(String overlayHtml)
{
this.overlayHtml = overlayHtml;
}
/*******************************************************************************
** Fluent setter for overlayHtml
*******************************************************************************/
public CompositeWidgetData withOverlayHtml(String overlayHtml)
{
this.overlayHtml = overlayHtml;
return (this);
}
/*******************************************************************************
** Getter for overlayStyleOverrides
*******************************************************************************/
public Map<String, Serializable> getOverlayStyleOverrides()
{
return (this.overlayStyleOverrides);
}
/*******************************************************************************
** Setter for overlayStyleOverrides
*******************************************************************************/
public void setOverlayStyleOverrides(Map<String, Serializable> overlayStyleOverrides)
{
this.overlayStyleOverrides = overlayStyleOverrides;
}
/*******************************************************************************
** Fluent setter for overlayStyleOverrides
*******************************************************************************/
public CompositeWidgetData withOverlayStyleOverrides(Map<String, Serializable> overlayStyleOverrides)
{
this.overlayStyleOverrides = overlayStyleOverrides;
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
public CompositeWidgetData withOverlayStyleOverride(String key, Serializable value)
{
addOverlayStyleOverride(key, value);
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
public void addOverlayStyleOverride(String key, Serializable value)
{
if(this.overlayStyleOverrides == null)
{
this.overlayStyleOverrides = new HashMap<>();
}
this.overlayStyleOverrides.put(key, value);
}
} }

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.CompositeWidgetData;
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.QWidgetData; import com.kingsrook.qqq.backend.core.model.dashboard.widgets.QWidgetData;
@ -74,6 +75,7 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withTooltip(S key, String value) public T withTooltip(S key, String value)
{ {
addTooltip(key, value); addTooltip(key, value);
@ -99,6 +101,7 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withTooltip(S key, BlockTooltip value) public T withTooltip(S key, BlockTooltip value)
{ {
addTooltip(key, value); addTooltip(key, value);
@ -144,6 +147,7 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** Fluent setter for tooltipMap ** Fluent setter for tooltipMap
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withTooltipMap(Map<S, BlockTooltip> tooltipMap) public T withTooltipMap(Map<S, BlockTooltip> tooltipMap)
{ {
this.tooltipMap = tooltipMap; this.tooltipMap = tooltipMap;
@ -178,6 +182,7 @@ public abstract class AbstractBlockWidgetData<
** Fluent setter for tooltip ** Fluent setter for tooltip
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withTooltip(String tooltip) public T withTooltip(String tooltip)
{ {
this.tooltip = new BlockTooltip(tooltip); this.tooltip = new BlockTooltip(tooltip);
@ -190,6 +195,7 @@ public abstract class AbstractBlockWidgetData<
** Fluent setter for tooltip ** Fluent setter for tooltip
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withTooltip(BlockTooltip tooltip) public T withTooltip(BlockTooltip tooltip)
{ {
this.tooltip = tooltip; this.tooltip = tooltip;
@ -199,8 +205,22 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** Fluent setter for tooltip
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withTooltip(CompositeWidgetData data)
{
this.tooltip = new BlockTooltip(data);
return (T) (this);
}
/*******************************************************************************
**
*******************************************************************************/
@SuppressWarnings("unchecked")
public T withLink(S key, String value) public T withLink(S key, String value)
{ {
addLink(key, value); addLink(key, value);
@ -226,6 +246,7 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withLink(S key, BlockLink value) public T withLink(S key, BlockLink value)
{ {
addLink(key, value); addLink(key, value);
@ -271,6 +292,7 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** Fluent setter for linkMap ** Fluent setter for linkMap
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withLinkMap(Map<S, BlockLink> linkMap) public T withLinkMap(Map<S, BlockLink> linkMap)
{ {
this.linkMap = linkMap; this.linkMap = linkMap;
@ -305,6 +327,7 @@ public abstract class AbstractBlockWidgetData<
** Fluent setter for link ** Fluent setter for link
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withLink(String link) public T withLink(String link)
{ {
this.link = new BlockLink(link); this.link = new BlockLink(link);
@ -317,6 +340,7 @@ public abstract class AbstractBlockWidgetData<
** Fluent setter for link ** Fluent setter for link
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withLink(BlockLink link) public T withLink(BlockLink link)
{ {
this.link = link; this.link = link;
@ -348,6 +372,7 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** Fluent setter for values ** Fluent setter for values
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withValues(V values) public T withValues(V values)
{ {
this.values = values; this.values = values;
@ -379,6 +404,7 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** Fluent setter for styles ** Fluent setter for styles
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withStyles(SX styles) public T withStyles(SX styles)
{ {
this.styles = styles; this.styles = styles;
@ -386,6 +412,7 @@ public abstract class AbstractBlockWidgetData<
} }
/******************************************************************************* /*******************************************************************************
** Getter for blockId ** Getter for blockId
*******************************************************************************/ *******************************************************************************/
@ -409,11 +436,11 @@ public abstract class AbstractBlockWidgetData<
/******************************************************************************* /*******************************************************************************
** Fluent setter for blockId ** Fluent setter for blockId
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public T withBlockId(String blockId) public T withBlockId(String blockId)
{ {
this.blockId = blockId; this.blockId = blockId;
return (T) this; return (T) this;
} }
} }

View File

@ -22,17 +22,24 @@
package com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks; package com.kingsrook.qqq.backend.core.model.dashboard.widgets.blocks;
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.CompositeWidgetData;
/******************************************************************************* /*******************************************************************************
** A tooltip used within a (widget) block. ** A tooltip used within a (widget) block.
** **
*******************************************************************************/ *******************************************************************************/
public class BlockTooltip public class BlockTooltip
{ {
private CompositeWidgetData blockData;
private String title; private String title;
private Placement placement = Placement.BOTTOM; private Placement placement = Placement.BOTTOM;
/***************************************************************************
**
***************************************************************************/
public enum Placement public enum Placement
{BOTTOM, LEFT, RIGHT, TOP} {BOTTOM, LEFT, RIGHT, TOP}
@ -59,6 +66,17 @@ public class BlockTooltip
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public BlockTooltip(CompositeWidgetData blockData)
{
this.blockData = blockData;
}
/******************************************************************************* /*******************************************************************************
** Getter for title ** Getter for title
*******************************************************************************/ *******************************************************************************/
@ -119,4 +137,35 @@ public class BlockTooltip
return (this); return (this);
} }
/*******************************************************************************
** Getter for blockData
*******************************************************************************/
public CompositeWidgetData getBlockData()
{
return (this.blockData);
}
/*******************************************************************************
** Setter for blockData
*******************************************************************************/
public void setBlockData(CompositeWidgetData blockData)
{
this.blockData = blockData;
}
/*******************************************************************************
** Fluent setter for blockData
*******************************************************************************/
public BlockTooltip withBlockData(CompositeWidgetData blockData)
{
this.blockData = blockData;
return (this);
}
} }

View File

@ -192,6 +192,7 @@ public abstract class QRecordEntity
for(QRecordEntityAssociation qRecordEntityAssociation : getAssociationList(this.getClass())) for(QRecordEntityAssociation qRecordEntityAssociation : getAssociationList(this.getClass()))
{ {
@SuppressWarnings("unchecked")
List<? extends QRecordEntity> associatedEntities = (List<? extends QRecordEntity>) qRecordEntityAssociation.getGetter().invoke(this); List<? extends QRecordEntity> associatedEntities = (List<? extends QRecordEntity>) qRecordEntityAssociation.getGetter().invoke(this);
String associationName = qRecordEntityAssociation.getAssociationAnnotation().name(); String associationName = qRecordEntityAssociation.getAssociationAnnotation().name();
@ -245,6 +246,7 @@ public abstract class QRecordEntity
for(QRecordEntityAssociation qRecordEntityAssociation : getAssociationList(this.getClass())) for(QRecordEntityAssociation qRecordEntityAssociation : getAssociationList(this.getClass()))
{ {
@SuppressWarnings("unchecked")
List<? extends QRecordEntity> associatedEntities = (List<? extends QRecordEntity>) qRecordEntityAssociation.getGetter().invoke(this); List<? extends QRecordEntity> associatedEntities = (List<? extends QRecordEntity>) qRecordEntityAssociation.getGetter().invoke(this);
String associationName = qRecordEntityAssociation.getAssociationAnnotation().name(); String associationName = qRecordEntityAssociation.getAssociationAnnotation().name();
@ -346,6 +348,7 @@ public abstract class QRecordEntity
if(associationAnnotation.isPresent()) if(associationAnnotation.isPresent())
{ {
@SuppressWarnings("unchecked")
Class<? extends QRecordEntity> listTypeParam = (Class<? extends QRecordEntity>) getListTypeParam(possibleGetter.getReturnType(), possibleGetter.getAnnotatedReturnType()); Class<? extends QRecordEntity> listTypeParam = (Class<? extends QRecordEntity>) getListTypeParam(possibleGetter.getReturnType(), possibleGetter.getAnnotatedReturnType());
associationList.add(new QRecordEntityAssociation(fieldName, possibleGetter, setter.get(), listTypeParam, associationAnnotation.orElse(null))); associationList.add(new QRecordEntityAssociation(fieldName, possibleGetter, setter.get(), listTypeParam, associationAnnotation.orElse(null)));
} }

View File

@ -53,6 +53,8 @@ public class QBackendMetaData implements TopLevelMetaDataInterface
private String variantOptionsTableUsernameField; private String variantOptionsTableUsernameField;
private String variantOptionsTablePasswordField; private String variantOptionsTablePasswordField;
private String variantOptionsTableApiKeyField; private String variantOptionsTableApiKeyField;
private String variantOptionsTableClientIdField;
private String variantOptionsTableClientSecretField;
private String variantOptionsTableName; private String variantOptionsTableName;
// todo - at some point, we may want to apply this to secret properties on subclasses? // todo - at some point, we may want to apply this to secret properties on subclasses?
@ -648,4 +650,66 @@ public class QBackendMetaData implements TopLevelMetaDataInterface
{ {
qInstance.addBackend(this); qInstance.addBackend(this);
} }
/*******************************************************************************
** Getter for variantOptionsTableClientIdField
*******************************************************************************/
public String getVariantOptionsTableClientIdField()
{
return (this.variantOptionsTableClientIdField);
}
/*******************************************************************************
** Setter for variantOptionsTableClientIdField
*******************************************************************************/
public void setVariantOptionsTableClientIdField(String variantOptionsTableClientIdField)
{
this.variantOptionsTableClientIdField = variantOptionsTableClientIdField;
}
/*******************************************************************************
** Fluent setter for variantOptionsTableClientIdField
*******************************************************************************/
public QBackendMetaData withVariantOptionsTableClientIdField(String variantOptionsTableClientIdField)
{
this.variantOptionsTableClientIdField = variantOptionsTableClientIdField;
return (this);
}
/*******************************************************************************
** Getter for variantOptionsTableClientSecretField
*******************************************************************************/
public String getVariantOptionsTableClientSecretField()
{
return (this.variantOptionsTableClientSecretField);
}
/*******************************************************************************
** Setter for variantOptionsTableClientSecretField
*******************************************************************************/
public void setVariantOptionsTableClientSecretField(String variantOptionsTableClientSecretField)
{
this.variantOptionsTableClientSecretField = variantOptionsTableClientSecretField;
}
/*******************************************************************************
** Fluent setter for variantOptionsTableClientSecretField
*******************************************************************************/
public QBackendMetaData withVariantOptionsTableClientSecretField(String variantOptionsTableClientSecretField)
{
this.variantOptionsTableClientSecretField = variantOptionsTableClientSecretField;
return (this);
}
} }

View File

@ -39,6 +39,9 @@ public class ParentWidgetMetaData extends QWidgetMetaData
/***************************************************************************
**
***************************************************************************/
public enum LayoutType public enum LayoutType
{ {
GRID, GRID,

View File

@ -188,7 +188,8 @@ public class FieldAdornment
** Fluent setter for values ** Fluent setter for values
** **
*******************************************************************************/ *******************************************************************************/
public FieldAdornment withValues(Pair<String, Serializable>... values) @SafeVarargs
public final FieldAdornment withValues(Pair<String, Serializable>... values)
{ {
for(Pair<String, Serializable> value : values) for(Pair<String, Serializable> value : values)
{ {

View File

@ -168,11 +168,11 @@ public class QFrontendTableMetaData
editPermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.EDIT); editPermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.EDIT);
deletePermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.DELETE); deletePermission = PermissionsHelper.hasTablePermission(actionInput, tableMetaData.getName(), TablePermissionSubType.DELETE);
QBackendMetaData backend = actionInput.getInstance().getBackend(tableMetaData.getBackendName()); QBackendMetaData backend = QContext.getQInstance().getBackend(tableMetaData.getBackendName());
if(backend != null && backend.getUsesVariants()) if(backend != null && backend.getUsesVariants())
{ {
usesVariants = true; usesVariants = true;
variantTableLabel = actionInput.getInstance().getTable(backend.getVariantOptionsTableName()).getLabel(); variantTableLabel = QContext.getQInstance().getTable(backend.getVariantOptionsTableName()).getLabel();
} }
this.helpContents = tableMetaData.getHelpContent(); this.helpContents = tableMetaData.getHelpContent();

View File

@ -32,6 +32,13 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
/******************************************************************************* /*******************************************************************************
** Meta-data definition of a source of data for a report (e.g., a table and query ** Meta-data definition of a source of data for a report (e.g., a table and query
** filter or custom-code reference). ** filter or custom-code reference).
**
** Runs in 3 modes:
**
** - If a customRecordSource is specified, then that code is executed to get the records.
** - else, if a sourceTable is specified, then the corresponding queryFilter
** (optionally along with queryJoins and queryInputCustomizer) is used.
** - else a staticDataSupplier is used.
*******************************************************************************/ *******************************************************************************/
public class QReportDataSource public class QReportDataSource
{ {
@ -44,6 +51,7 @@ public class QReportDataSource
private QCodeReference queryInputCustomizer; private QCodeReference queryInputCustomizer;
private QCodeReference staticDataSupplier; private QCodeReference staticDataSupplier;
private QCodeReference customRecordSource;
@ -265,4 +273,35 @@ public class QReportDataSource
return (this); return (this);
} }
/*******************************************************************************
** Getter for customRecordSource
*******************************************************************************/
public QCodeReference getCustomRecordSource()
{
return (this.customRecordSource);
}
/*******************************************************************************
** Setter for customRecordSource
*******************************************************************************/
public void setCustomRecordSource(QCodeReference customRecordSource)
{
this.customRecordSource = customRecordSource;
}
/*******************************************************************************
** Fluent setter for customRecordSource
*******************************************************************************/
public QReportDataSource withCustomRecordSource(QCodeReference customRecordSource)
{
this.customRecordSource = customRecordSource;
return (this);
}
} }

View File

@ -804,7 +804,7 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
{ {
if(this.associatedScripts == null) if(this.associatedScripts == null)
{ {
this.associatedScripts = new ArrayList(); this.associatedScripts = new ArrayList<>();
} }
this.associatedScripts.add(associatedScript); this.associatedScripts.add(associatedScript);
return (this); return (this);

View File

@ -32,6 +32,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
*******************************************************************************/ *******************************************************************************/
public class CacheUseCase public class CacheUseCase
{ {
/***************************************************************************
**
***************************************************************************/
public enum Type public enum Type
{ {
PRIMARY_KEY_TO_PRIMARY_KEY, // e.g., the primary key in the cache table equals the primary key in the source table. PRIMARY_KEY_TO_PRIMARY_KEY, // e.g., the primary key in the cache table equals the primary key in the source table.

View File

@ -662,7 +662,11 @@ public class MemoryRecordStore
{ {
return (-1); return (-1);
} }
return ((Comparable) a).compareTo(b);
@SuppressWarnings("unchecked")
Comparable<Serializable> comparableSerializableA = (Comparable<Serializable>) a;
return comparableSerializableA.compareTo(b);
}; };
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -769,6 +773,7 @@ public class MemoryRecordStore
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Serializable computeAggregate(List<QRecord> records, Aggregate aggregate, QTableMetaData table) private static Serializable computeAggregate(List<QRecord> records, Aggregate aggregate, QTableMetaData table)
{ {
String fieldName = aggregate.getFieldName(); String fieldName = aggregate.getFieldName();

View File

@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
@ -76,7 +77,7 @@ public class BulkDeleteLoadStep extends LoadViaDeleteStep implements ProcessSumm
{ {
super.preRun(runBackendStepInput, runBackendStepOutput); super.preRun(runBackendStepInput, runBackendStepOutput);
QTableMetaData table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
if(table != null) if(table != null)
{ {
tableLabel = table.getLabel(); tableLabel = table.getLabel();
@ -119,7 +120,7 @@ public class BulkDeleteLoadStep extends LoadViaDeleteStep implements ProcessSumm
//////////////////////////// ////////////////////////////
super.runOnePage(runBackendStepInput, runBackendStepOutput); super.runOnePage(runBackendStepInput, runBackendStepOutput);
QTableMetaData table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
String primaryKeyFieldName = table.getPrimaryKeyField(); String primaryKeyFieldName = table.getPrimaryKeyField();
Map<Serializable, QRecord> outputRecordMap = runBackendStepOutput.getRecords().stream().collect(Collectors.toMap(r -> r.getValue(primaryKeyFieldName), r -> r, (a, b) -> a)); Map<Serializable, QRecord> outputRecordMap = runBackendStepOutput.getRecords().stream().collect(Collectors.toMap(r -> r.getValue(primaryKeyFieldName), r -> r, (a, b) -> a));

View File

@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
@ -65,7 +66,7 @@ public class BulkDeleteTransformStep extends AbstractTransformStep
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// capture the table label - for the process summary // // capture the table label - for the process summary //
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
QTableMetaData table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
if(table != null) if(table != null)
{ {
tableLabel = table.getLabel(); tableLabel = table.getLabel();

View File

@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.processes.implementations.bulk.edit;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
@ -99,7 +100,7 @@ public class BulkEditLoadStep extends LoadViaUpdateStep implements ProcessSummar
{ {
super.preRun(runBackendStepInput, runBackendStepOutput); super.preRun(runBackendStepInput, runBackendStepOutput);
QTableMetaData table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
if(table != null) if(table != null)
{ {
tableLabel = table.getLabel(); tableLabel = table.getLabel();
@ -124,7 +125,7 @@ public class BulkEditLoadStep extends LoadViaUpdateStep implements ProcessSummar
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
// roll up results based on output from update action // // roll up results based on output from update action //
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
QTableMetaData table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
for(QRecord record : runBackendStepOutput.getRecords()) for(QRecord record : runBackendStepOutput.getRecords())
{ {
Serializable recordPrimaryKey = record.getValue(table.getPrimaryKeyField()); Serializable recordPrimaryKey = record.getValue(table.getPrimaryKeyField());

View File

@ -31,6 +31,7 @@ import java.util.Optional;
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator; import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
@ -81,7 +82,7 @@ public class BulkEditTransformStep extends AbstractTransformStep
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// capture the table label - for the process summary // // capture the table label - for the process summary //
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
if(table != null) if(table != null)
{ {
tableLabel = table.getLabel(); tableLabel = table.getLabel();
@ -230,7 +231,7 @@ public class BulkEditTransformStep extends AbstractTransformStep
if(field.getPossibleValueSourceName() != null) if(field.getPossibleValueSourceName() != null)
{ {
QPossibleValueTranslator qPossibleValueTranslator = new QPossibleValueTranslator(runBackendStepInput.getInstance(), runBackendStepInput.getSession()); QPossibleValueTranslator qPossibleValueTranslator = new QPossibleValueTranslator(QContext.getQInstance(), QContext.getQSession());
String translatedValue = qPossibleValueTranslator.translatePossibleValue(field, value); String translatedValue = qPossibleValueTranslator.translatePossibleValue(field, value);
if(StringUtils.hasContent(translatedValue)) if(StringUtils.hasContent(translatedValue))
{ {

View File

@ -27,6 +27,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import com.kingsrook.qqq.backend.core.adapters.CsvToQRecordAdapter; import com.kingsrook.qqq.backend.core.adapters.CsvToQRecordAdapter;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.model.actions.processes.QUploadedFile; import com.kingsrook.qqq.backend.core.model.actions.processes.QUploadedFile;
@ -83,7 +84,7 @@ public class BulkInsertExtractStep extends AbstractExtractStep
.withLimit(getLimit()) .withLimit(getLimit())
.withCsv(new String(bytes)) .withCsv(new String(bytes))
.withDoCorrectValueTypes(true) .withDoCorrectValueTypes(true)
.withTable(runBackendStepInput.getInstance().getTable(tableName)) .withTable(QContext.getQInstance().getTable(tableName))
.withMapping(mapping) .withMapping(mapping)
.withRecordCustomizer((record) -> .withRecordCustomizer((record) ->
{ {

View File

@ -38,6 +38,7 @@ import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizerInterfa
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.actions.tables.helpers.UniqueKeyHelper; import com.kingsrook.qqq.backend.core.actions.tables.helpers.UniqueKeyHelper;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface; import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
@ -104,7 +105,7 @@ public class BulkInsertTransformStep extends AbstractTransformStep
@Override @Override
public void preRun(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException public void preRun(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{ {
this.table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); this.table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// since we're doing a unique key check in this class, we can tell the loadViaInsert step that it (rather, the InsertAction) doesn't need to re-do one. // // since we're doing a unique key check in this class, we can tell the loadViaInsert step that it (rather, the InsertAction) doesn't need to re-do one. //
@ -121,7 +122,7 @@ public class BulkInsertTransformStep extends AbstractTransformStep
public void runOnePage(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException public void runOnePage(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{ {
int rowsInThisPage = runBackendStepInput.getRecords().size(); int rowsInThisPage = runBackendStepInput.getRecords().size();
QTableMetaData table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getTableName()); QTableMetaData table = QContext.getQInstance().getTable(runBackendStepInput.getTableName());
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// set up an insert-input, which will be used as input to the pre-customizer as well as for additional validations // // set up an insert-input, which will be used as input to the pre-customizer as well as for additional validations //

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.List; 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.adapters.JsonToQFieldMappingAdapter; import com.kingsrook.qqq.backend.core.adapters.JsonToQFieldMappingAdapter;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
@ -85,7 +86,7 @@ public class BasicETLTransformFunction implements BackendStep
throw (new QException("Mapping was not a Key-based mapping type. Was a : " + mapping.getClass().getName())); throw (new QException("Mapping was not a Key-based mapping type. Was a : " + mapping.getClass().getName()));
} }
QTableMetaData table = runBackendStepInput.getInstance().getTable(tableName); QTableMetaData table = QContext.getQInstance().getTable(tableName);
List<QRecord> mappedRecords = applyMapping(runBackendStepInput.getRecords(), table, keyBasedFieldMapping); List<QRecord> mappedRecords = applyMapping(runBackendStepInput.getRecords(), table, keyBasedFieldMapping);
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -27,6 +27,7 @@ import java.util.List;
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader; import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator; import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
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;
@ -85,14 +86,14 @@ public class BaseStreamedETLStep
protected void updateRecordsWithDisplayValuesAndPossibleValues(RunBackendStepInput input, List<QRecord> list) protected void updateRecordsWithDisplayValuesAndPossibleValues(RunBackendStepInput input, List<QRecord> list)
{ {
String destinationTable = input.getValueString(StreamedETLWithFrontendProcess.FIELD_DESTINATION_TABLE); String destinationTable = input.getValueString(StreamedETLWithFrontendProcess.FIELD_DESTINATION_TABLE);
QTableMetaData table = input.getInstance().getTable(destinationTable); QTableMetaData table = QContext.getQInstance().getTable(destinationTable);
if(table != null && list != null) if(table != null && list != null)
{ {
QValueFormatter qValueFormatter = new QValueFormatter(); QValueFormatter qValueFormatter = new QValueFormatter();
qValueFormatter.setDisplayValuesInRecords(table, list); qValueFormatter.setDisplayValuesInRecords(table, list);
QPossibleValueTranslator qPossibleValueTranslator = new QPossibleValueTranslator(input.getInstance(), input.getSession()); QPossibleValueTranslator qPossibleValueTranslator = new QPossibleValueTranslator(QContext.getQInstance(), QContext.getQSession());
qPossibleValueTranslator.translatePossibleValuesInRecords(table, list); qPossibleValueTranslator.translatePossibleValuesInRecords(table, list);
} }
} }

View File

@ -34,6 +34,7 @@ import com.kingsrook.qqq.backend.core.actions.reporting.DistinctFilteringRecordP
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe; import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
import com.kingsrook.qqq.backend.core.actions.tables.CountAction; import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
@ -267,7 +268,7 @@ public class ExtractViaQueryStep extends AbstractExtractStep
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// else, check for recordIds from a frontend launching of a process // // else, check for recordIds from a frontend launching of a process //
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
QTableMetaData table = runBackendStepInput.getInstance().getTable(runBackendStepInput.getValueString(FIELD_SOURCE_TABLE)); QTableMetaData table = QContext.getQInstance().getTable(runBackendStepInput.getValueString(FIELD_SOURCE_TABLE));
if(table == null) if(table == null)
{ {
throw (new QException("source table name was not set - could not load records by id")); throw (new QException("source table name was not set - could not load records by id"));
@ -319,7 +320,7 @@ public class ExtractViaQueryStep extends AbstractExtractStep
if(needDistinctPipe) if(needDistinctPipe)
{ {
String sourceTableName = runBackendStepInput.getValueString(StreamedETLWithFrontendProcess.FIELD_SOURCE_TABLE); String sourceTableName = runBackendStepInput.getValueString(StreamedETLWithFrontendProcess.FIELD_SOURCE_TABLE);
QTableMetaData sourceTable = runBackendStepInput.getInstance().getTable(sourceTableName); QTableMetaData sourceTable = QContext.getQInstance().getTable(sourceTableName);
return (new DistinctFilteringRecordPipe(new UniqueKey(sourceTable.getPrimaryKeyField()), overrideCapacity)); return (new DistinctFilteringRecordPipe(new UniqueKey(sourceTable.getPrimaryKeyField()), overrideCapacity));
} }
else else

View File

@ -28,6 +28,7 @@ import java.util.Optional;
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction; import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
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;
@ -86,7 +87,7 @@ public class LoadViaInsertOrUpdateStep extends AbstractLoadStep
*******************************************************************************/ *******************************************************************************/
public void insertAndUpdateRecords(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException public void insertAndUpdateRecords(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{ {
QTableMetaData tableMetaData = runBackendStepInput.getInstance().getTable(runBackendStepInput.getValueString(FIELD_DESTINATION_TABLE)); QTableMetaData tableMetaData = QContext.getQInstance().getTable(runBackendStepInput.getValueString(FIELD_DESTINATION_TABLE));
if(CollectionUtils.nullSafeHasContents(recordsToInsert)) if(CollectionUtils.nullSafeHasContents(recordsToInsert))
{ {
@ -139,7 +140,7 @@ public class LoadViaInsertOrUpdateStep extends AbstractLoadStep
*******************************************************************************/ *******************************************************************************/
protected void evaluateRecords(RunBackendStepInput runBackendStepInput) throws QException protected void evaluateRecords(RunBackendStepInput runBackendStepInput) throws QException
{ {
QTableMetaData tableMetaData = runBackendStepInput.getInstance().getTable(runBackendStepInput.getValueString(FIELD_DESTINATION_TABLE)); QTableMetaData tableMetaData = QContext.getQInstance().getTable(runBackendStepInput.getValueString(FIELD_DESTINATION_TABLE));
recordsToInsert = new ArrayList<>(); recordsToInsert = new ArrayList<>();
recordsToUpdate = new ArrayList<>(); recordsToUpdate = new ArrayList<>();

View File

@ -162,10 +162,10 @@ public class StreamedETLPreviewStep extends BaseStreamedETLStep implements Backe
private void countRecords(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput, AbstractExtractStep extractStep) throws QException private void countRecords(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput, AbstractExtractStep extractStep) throws QException
{ {
String sourceTableName = runBackendStepInput.getValueString(StreamedETLWithFrontendProcess.FIELD_SOURCE_TABLE); String sourceTableName = runBackendStepInput.getValueString(StreamedETLWithFrontendProcess.FIELD_SOURCE_TABLE);
QTableMetaData sourceTable = runBackendStepInput.getInstance().getTable(sourceTableName); QTableMetaData sourceTable = QContext.getQInstance().getTable(sourceTableName);
if(StringUtils.hasContent(sourceTableName)) if(StringUtils.hasContent(sourceTableName))
{ {
QBackendMetaData sourceTableBackend = runBackendStepInput.getInstance().getBackendForTable(sourceTableName); QBackendMetaData sourceTableBackend = QContext.getQInstance().getBackendForTable(sourceTableName);
if(sourceTable.isCapabilityEnabled(sourceTableBackend, Capability.TABLE_COUNT)) if(sourceTable.isCapabilityEnabled(sourceTableBackend, Capability.TABLE_COUNT))
{ {
Integer recordCount = extractStep.doCount(runBackendStepInput); Integer recordCount = extractStep.doCount(runBackendStepInput);

View File

@ -65,8 +65,13 @@ public class MergeDuplicatesLoadStep extends LoadViaInsertOrUpdateStep
{ {
super.runOnePage(runBackendStepInput, runBackendStepOutput); super.runOnePage(runBackendStepInput, runBackendStepOutput);
@SuppressWarnings("unchecked")
ListingHash<String, Serializable> otherTableIdsToDelete = (ListingHash<String, Serializable>) runBackendStepInput.getValue("otherTableIdsToDelete"); ListingHash<String, Serializable> otherTableIdsToDelete = (ListingHash<String, Serializable>) runBackendStepInput.getValue("otherTableIdsToDelete");
@SuppressWarnings("unchecked")
ListingHash<String, QQueryFilter> otherTableFiltersToDelete = (ListingHash<String, QQueryFilter>) runBackendStepInput.getValue("otherTableFiltersToDelete"); ListingHash<String, QQueryFilter> otherTableFiltersToDelete = (ListingHash<String, QQueryFilter>) runBackendStepInput.getValue("otherTableFiltersToDelete");
@SuppressWarnings("unchecked")
ListingHash<String, QRecord> otherTableRecordsToStore = (ListingHash<String, QRecord>) runBackendStepInput.getValue("otherTableRecordsToStore"); ListingHash<String, QRecord> otherTableRecordsToStore = (ListingHash<String, QRecord>) runBackendStepInput.getValue("otherTableRecordsToStore");
if(otherTableIdsToDelete != null) if(otherTableIdsToDelete != null)

View File

@ -47,6 +47,7 @@ public class BasicRunReportProcess
public static final String STEP_NAME_ACCESS = "accessReport"; public static final String STEP_NAME_ACCESS = "accessReport";
public static final String FIELD_REPORT_NAME = "reportName"; public static final String FIELD_REPORT_NAME = "reportName";
public static final String FIELD_REPORT_FORMAT = "reportFormat";

View File

@ -31,7 +31,9 @@ import java.time.format.DateTimeFormatter;
import java.util.Map; import java.util.Map;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction; import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
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.actions.reporting.ReportDestination; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination;
@ -49,6 +51,7 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
public class ExecuteReportStep implements BackendStep public class ExecuteReportStep implements BackendStep
{ {
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -57,9 +60,10 @@ public class ExecuteReportStep implements BackendStep
{ {
try try
{ {
ReportFormat reportFormat = getReportFormat(runBackendStepInput);
String reportName = runBackendStepInput.getValueString("reportName"); String reportName = runBackendStepInput.getValueString("reportName");
QReportMetaData report = runBackendStepInput.getInstance().getReport(reportName); QReportMetaData report = QContext.getQInstance().getReport(reportName);
File tmpFile = File.createTempFile(reportName, ".xlsx", new File("/tmp/")); File tmpFile = File.createTempFile(reportName, "." + reportFormat.getExtension());
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report"); runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
@ -68,7 +72,7 @@ public class ExecuteReportStep implements BackendStep
ReportInput reportInput = new ReportInput(); ReportInput reportInput = new ReportInput();
reportInput.setReportName(reportName); reportInput.setReportName(reportName);
reportInput.setReportDestination(new ReportDestination() reportInput.setReportDestination(new ReportDestination()
.withReportFormat(ReportFormat.XLSX) // todo - variable .withReportFormat(reportFormat)
.withReportOutputStream(reportOutputStream)); .withReportOutputStream(reportOutputStream));
Map<String, Serializable> values = runBackendStepInput.getValues(); Map<String, Serializable> values = runBackendStepInput.getValues();
@ -78,7 +82,7 @@ public class ExecuteReportStep implements BackendStep
String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, report); String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, report);
runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + ".xlsx"); runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + "." + reportFormat.getExtension());
runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath()); runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath());
} }
} }
@ -90,6 +94,22 @@ public class ExecuteReportStep implements BackendStep
/***************************************************************************
**
***************************************************************************/
private ReportFormat getReportFormat(RunBackendStepInput runBackendStepInput) throws QUserFacingException
{
String reportFormatInput = runBackendStepInput.getValueString(BasicRunReportProcess.FIELD_REPORT_FORMAT);
if(StringUtils.hasContent(reportFormatInput))
{
return (ReportFormat.fromString(reportFormatInput));
}
return (ReportFormat.XLSX);
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -26,6 +26,7 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
@ -106,15 +107,16 @@ public class PrepareReportForRecordStep extends PrepareReportStep
} }
String reportName = runBackendStepInput.getValueString("reportName"); String reportName = runBackendStepInput.getValueString("reportName");
QReportMetaData report = runBackendStepInput.getInstance().getReport(reportName); QReportMetaData report = QContext.getQInstance().getReport(reportName);
// runBackendStepOutput.addValue("downloadFileBaseName", runBackendStepInput.getTable().getLabel() + " " + record.getRecordLabel()); // runBackendStepOutput.addValue("downloadFileBaseName", runBackendStepInput.getTable().getLabel() + " " + record.getRecordLabel());
runBackendStepOutput.addValue("downloadFileBaseName", report.getLabel() + " - " + record.getRecordLabel()); runBackendStepOutput.addValue("downloadFileBaseName", report.getLabel() + " - " + record.getRecordLabel());
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
// if there are no more input fields, then remove the INPUT step from the process. // // if there are no more input fields, then remove the INPUT step from the process. //
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
inputFieldList = (ArrayList<QFieldMetaData>) runBackendStepOutput.getValue("inputFieldList"); @SuppressWarnings("unchecked")
if(!CollectionUtils.nullSafeHasContents(inputFieldList)) ArrayList<QFieldMetaData> updatedInputFieldList = (ArrayList<QFieldMetaData>) runBackendStepOutput.getValue("inputFieldList");
if(!CollectionUtils.nullSafeHasContents(updatedInputFieldList))
{ {
removeInputStepFromProcess(runBackendStepOutput); removeInputStepFromProcess(runBackendStepOutput);
} }

View File

@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.processes.implementations.reports;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
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;
@ -56,7 +57,7 @@ public class PrepareReportStep implements BackendStep
throw (new QException("Process value [reportName] was not given.")); throw (new QException("Process value [reportName] was not given."));
} }
QReportMetaData report = runBackendStepInput.getInstance().getReport(reportName); QReportMetaData report = QContext.getQInstance().getReport(reportName);
if(report == null) if(report == null)
{ {
throw (new QException("Process named [" + reportName + "] was not found in this instance.")); throw (new QException("Process named [" + reportName + "] was not found in this instance."));

View File

@ -29,6 +29,7 @@ import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
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;
@ -44,6 +45,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
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.model.savedviews.SavedView; import com.kingsrook.qqq.backend.core.model.savedviews.SavedView;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/******************************************************************************* /*******************************************************************************
@ -78,10 +80,10 @@ public class QuerySavedViewProcess implements BackendStep
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{ {
ActionHelper.validateSession(runBackendStepInput); ActionHelper.validateSession(runBackendStepInput);
Integer savedViewId = runBackendStepInput.getValueInteger("id");
try try
{ {
Integer savedViewId = runBackendStepInput.getValueInteger("id");
if(savedViewId != null) if(savedViewId != null)
{ {
GetInput input = new GetInput(); GetInput input = new GetInput();
@ -89,6 +91,11 @@ public class QuerySavedViewProcess implements BackendStep
input.setPrimaryKey(savedViewId); input.setPrimaryKey(savedViewId);
GetOutput output = new GetAction().execute(input); GetOutput output = new GetAction().execute(input);
if(output.getRecord() == null)
{
throw (new QNotFoundException("The requested view was not found."));
}
runBackendStepOutput.addRecord(output.getRecord()); runBackendStepOutput.addRecord(output.getRecord());
runBackendStepOutput.addValue("savedView", output.getRecord()); runBackendStepOutput.addValue("savedView", output.getRecord());
runBackendStepOutput.addValue("savedViewList", (Serializable) List.of(output.getRecord())); runBackendStepOutput.addValue("savedViewList", (Serializable) List.of(output.getRecord()));
@ -108,6 +115,11 @@ public class QuerySavedViewProcess implements BackendStep
runBackendStepOutput.addValue("savedViewList", (Serializable) output.getRecords()); runBackendStepOutput.addValue("savedViewList", (Serializable) output.getRecords());
} }
} }
catch(QNotFoundException qnfe)
{
LOG.info("View not found", logPair("savedViewId", savedViewId));
throw (qnfe);
}
catch(Exception e) catch(Exception e)
{ {
LOG.warn("Error querying for saved views", e); LOG.warn("Error querying for saved views", e);

View File

@ -145,7 +145,7 @@ public class StoreScriptRevisionProcessStep implements BackendStep
try try
{ {
scriptRevision.setValue("author", input.getSession().getUser().getFullName()); scriptRevision.setValue("author", QContext.getQSession().getUser().getFullName());
} }
catch(Exception e) catch(Exception e)
{ {

View File

@ -139,7 +139,7 @@ public class TestScriptProcessStep implements BackendStep
////////////////////////////////// //////////////////////////////////
// send script outputs back out // // send script outputs back out //
////////////////////////////////// //////////////////////////////////
output.addValue("scriptLogLines", CollectionUtils.useOrWrap(testScriptOutput.getScriptLogLines(), TypeToken.get(ArrayList.class))); output.addValue("scriptLogLines", CollectionUtils.useOrWrap(testScriptOutput.getScriptLogLines(), new TypeToken<ArrayList<QRecord>>() {}));
output.addValue("outputObject", testScriptOutput.getOutputObject()); output.addValue("outputObject", testScriptOutput.getOutputObject());
if(testScriptOutput.getException() != null) if(testScriptOutput.getException() != null)

View File

@ -365,10 +365,10 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
{ {
if(possibleValueTranslator == null) if(possibleValueTranslator == null)
{ {
possibleValueTranslator = new QPossibleValueTranslator(runBackendStepInput.getInstance(), runBackendStepInput.getSession()); possibleValueTranslator = new QPossibleValueTranslator(QContext.getQInstance(), QContext.getQSession());
} }
possibleValueTranslator.translatePossibleValuesInRecords(runBackendStepInput.getInstance().getTable(destinationTableName), runBackendStepOutput.getRecords()); possibleValueTranslator.translatePossibleValuesInRecords(QContext.getQInstance().getTable(destinationTableName), runBackendStepOutput.getRecords());
} }
} }
} }

View File

@ -433,6 +433,8 @@ public class ProcessLockUtils
{ {
throw (new QException("Error deleting processLock record: " + deleteOutput.getRecordsWithErrors().get(0).getErrorsAsString())); throw (new QException("Error deleting processLock record: " + deleteOutput.getRecordsWithErrors().get(0).getErrorsAsString()));
} }
LOG.info("Released process lock", logPair("id", processLock.getId()), logPair("key", processLock.getKey()), logPair("typeId", processLock.getProcessLockTypeId()), logPair("details", processLock.getDetails()));
} }
catch(QException e) catch(QException e)
{ {

View File

@ -32,6 +32,7 @@ import java.util.function.Consumer;
import com.kingsrook.qqq.backend.core.actions.tables.CountAction; import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
@ -515,7 +516,7 @@ public class GeneralProcessUtils
*******************************************************************************/ *******************************************************************************/
public static Integer validateSingleSelectedId(RunBackendStepInput runBackendStepInput, String tableName) throws QException public static Integer validateSingleSelectedId(RunBackendStepInput runBackendStepInput, String tableName) throws QException
{ {
String tableLabel = runBackendStepInput.getInstance().getTable(tableName).getLabel(); String tableLabel = QContext.getQInstance().getTable(tableName).getLabel();
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// Get the selected recordId and verify we only 1 // // Get the selected recordId and verify we only 1 //

View File

@ -70,7 +70,9 @@ public class QuartzJobRunner implements Job
QContext.init(qInstance, quartzScheduler.getSessionSupplier().get()); QContext.init(qInstance, quartzScheduler.getSessionSupplier().get());
schedulableType = qInstance.getSchedulableType(context.getJobDetail().getJobDataMap().getString("type")); schedulableType = qInstance.getSchedulableType(context.getJobDetail().getJobDataMap().getString("type"));
params = (Map<String, Object>) context.getJobDetail().getJobDataMap().get("params"); @SuppressWarnings("unchecked")
Map<String, Object> paramsFromJobDataMap = (Map<String, Object>) context.getJobDetail().getJobDataMap().get("params");
params = paramsFromJobDataMap;
SchedulableRunner schedulableRunner = QCodeLoader.getAdHoc(SchedulableRunner.class, schedulableType.getRunner()); SchedulableRunner schedulableRunner = QCodeLoader.getAdHoc(SchedulableRunner.class, schedulableType.getRunner());

View File

@ -74,7 +74,9 @@ public class SchedulableProcessRunner implements SchedulableRunner
Map<String, Serializable> backendVariantData = null; Map<String, Serializable> backendVariantData = null;
if(params.containsKey("backendVariantData")) if(params.containsKey("backendVariantData"))
{ {
backendVariantData = (Map<String, Serializable>) params.get("backendVariantData"); @SuppressWarnings("unchecked")
Map<String, Serializable> dataFromMap = (Map<String, Serializable>) params.get("backendVariantData");
backendVariantData = dataFromMap;
} }
Map<String, Serializable> processInputValues = buildProcessInputValuesMap(params, process); Map<String, Serializable> processInputValues = buildProcessInputValuesMap(params, process);

View File

@ -26,6 +26,7 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
import java.time.Instant; import java.time.Instant;
import java.util.Optional; import java.util.Optional;
@ -78,7 +79,7 @@ public class TempFileStateProvider implements StateProviderInterface
try try
{ {
String json = JsonUtils.toJson(data); String json = JsonUtils.toJson(data);
FileUtils.writeStringToFile(getFile(key), json); FileUtils.writeStringToFile(getFile(key), json, StandardCharsets.UTF_8);
} }
catch(IOException e) catch(IOException e)
{ {
@ -97,7 +98,7 @@ public class TempFileStateProvider implements StateProviderInterface
{ {
try try
{ {
String json = FileUtils.readFileToString(getFile(key)); String json = FileUtils.readFileToString(getFile(key), StandardCharsets.UTF_8);
return (Optional.of(JsonUtils.toObject(json, type))); return (Optional.of(JsonUtils.toObject(json, type)));
} }
catch(FileNotFoundException | NoSuchFileException fnfe) catch(FileNotFoundException | NoSuchFileException fnfe)

View File

@ -50,7 +50,7 @@ public class CollectionUtils
** true if c is null or it's empty ** true if c is null or it's empty
** **
*******************************************************************************/ *******************************************************************************/
public static boolean nullSafeIsEmpty(Collection c) public static boolean nullSafeIsEmpty(Collection<?> c)
{ {
if(c == null || c.isEmpty()) if(c == null || c.isEmpty())
{ {
@ -66,7 +66,7 @@ public class CollectionUtils
** true if c is null or it's empty ** true if c is null or it's empty
** **
*******************************************************************************/ *******************************************************************************/
public static boolean nullSafeIsEmpty(Map c) public static boolean nullSafeIsEmpty(Map<?, ?> c)
{ {
if(c == null || c.isEmpty()) if(c == null || c.isEmpty())
{ {
@ -82,7 +82,7 @@ public class CollectionUtils
** true if c is NOT null and it's not empty ** true if c is NOT null and it's not empty
** **
*******************************************************************************/ *******************************************************************************/
public static boolean nullSafeHasContents(Collection c) public static boolean nullSafeHasContents(Collection<?> c)
{ {
return (!nullSafeIsEmpty(c)); return (!nullSafeIsEmpty(c));
} }
@ -93,7 +93,7 @@ public class CollectionUtils
** true if c is NOT null and it's not empty ** true if c is NOT null and it's not empty
** **
*******************************************************************************/ *******************************************************************************/
public static boolean nullSafeHasContents(Map c) public static boolean nullSafeHasContents(Map<?, ?> c)
{ {
return (!nullSafeIsEmpty(c)); return (!nullSafeIsEmpty(c));
} }
@ -104,7 +104,7 @@ public class CollectionUtils
** 0 if c is empty, otherwise, its size. ** 0 if c is empty, otherwise, its size.
** **
*******************************************************************************/ *******************************************************************************/
public static int nullSafeSize(Collection c) public static int nullSafeSize(Collection<?> c)
{ {
if(c == null) if(c == null)
{ {
@ -120,7 +120,7 @@ public class CollectionUtils
** 0 if c is empty, otherwise, its size. ** 0 if c is empty, otherwise, its size.
** **
*******************************************************************************/ *******************************************************************************/
public static int nullSafeSize(Map c) public static int nullSafeSize(Map<?, ?> c)
{ {
if(c == null) if(c == null)
{ {
@ -302,14 +302,14 @@ public class CollectionUtils
return (rs); return (rs);
} }
List<T> currentPage = new LinkedList<T>(); List<T> currentPage = new LinkedList<>();
rs.add(currentPage); rs.add(currentPage);
for(T value : values) for(T value : values)
{ {
if(currentPage.size() >= pageSize) if(currentPage.size() >= pageSize)
{ {
currentPage = new LinkedList<T>(); currentPage = new LinkedList<>();
rs.add(currentPage); rs.add(currentPage);
} }
@ -423,6 +423,7 @@ public class CollectionUtils
** **
** Meant to help avoid null checks on foreach loops. ** Meant to help avoid null checks on foreach loops.
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings("unchecked")
public static <T> T[] nonNullArray(T[] array) public static <T> T[] nonNullArray(T[] array)
{ {
if(array == null) if(array == null)
@ -539,7 +540,7 @@ public class CollectionUtils
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public static Map objectToMap(Object o) public static Map<?, ?> objectToMap(Object o)
{ {
ObjectMapper mapper = new ObjectMapper() ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule()) .registerModule(new JavaTimeModule())
@ -555,6 +556,7 @@ public class CollectionUtils
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@SafeVarargs
public static <T> List<T> mergeLists(List<T>... lists) public static <T> List<T> mergeLists(List<T>... lists)
{ {
List<T> rs = new ArrayList<>(); List<T> rs = new ArrayList<>();
@ -593,6 +595,7 @@ public class CollectionUtils
return (null); return (null);
} }
@SuppressWarnings("unchecked")
Class<T> targetClass = (Class<T>) typeToken.getRawType(); Class<T> targetClass = (Class<T>) typeToken.getRawType();
if(targetClass.isInstance(collection)) if(targetClass.isInstance(collection))
{ {
@ -630,6 +633,7 @@ public class CollectionUtils
return (null); return (null);
} }
@SuppressWarnings("unchecked")
Class<T> targetClass = (Class<T>) typeToken.getRawType(); Class<T> targetClass = (Class<T>) typeToken.getRawType();
if(targetClass.isInstance(collection)) if(targetClass.isInstance(collection))
{ {

View File

@ -0,0 +1,126 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. 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.utils;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.kingsrook.qqq.backend.core.utils.collections.MutableMap;
/*******************************************************************************
** Hash that provides "counting" capability -- keys map to Integers that
** are automatically/easily summed to
**
*******************************************************************************/
public class CountingHash<K extends Serializable> extends AbstractMap<K, Integer> implements Serializable
{
private Map<K, Integer> map = null;
/*******************************************************************************
** Default constructor
**
*******************************************************************************/
public CountingHash()
{
this.map = new HashMap<>();
}
/*******************************************************************************
** Constructor where you can supply a source map (e.g., if you want a specific
** Map type (like LinkedHashMap), or with pre-values.
**
** Note - the input map will be wrapped in a MutableMap - so - it'll be mutable.
**
*******************************************************************************/
public CountingHash(Map<K, Integer> sourceMap)
{
this.map = new MutableMap<>(sourceMap);
}
/*******************************************************************************
** Increment the value for the specified key by 1.
**
*******************************************************************************/
public Integer add(K key)
{
Integer value = getOrCreateListForKey(key);
Integer sum = value + 1;
map.put(key, sum);
return (sum);
}
/*******************************************************************************
** Increment the value for the specified key by the supplied addend
**
*******************************************************************************/
public Integer add(K key, Integer addend)
{
Integer value = getOrCreateListForKey(key);
Integer sum = value + addend;
map.put(key, sum);
return (sum);
}
/*******************************************************************************
**
*******************************************************************************/
private Integer getOrCreateListForKey(K key)
{
Integer value;
if(!this.map.containsKey(key))
{
this.map.put(key, 0);
value = 0;
}
else
{
value = this.map.get(key);
}
return value;
}
/***************************************************************************
*
***************************************************************************/
public Set<Entry<K, Integer>> entrySet()
{
return this.map.entrySet();
}
}

View File

@ -37,6 +37,7 @@ public class ObjectUtils
/******************************************************************************* /*******************************************************************************
** A varargs version of Objects.requireNonNullElse ** A varargs version of Objects.requireNonNullElse
*******************************************************************************/ *******************************************************************************/
@SafeVarargs
public static <T> T requireNonNullElse(T... objects) public static <T> T requireNonNullElse(T... objects)
{ {
if(objects == null) if(objects == null)

View File

@ -888,6 +888,7 @@ public class ValueUtils
** Return the first argument that isn't null. ** Return the first argument that isn't null.
** If all were null, return null. ** If all were null, return null.
*******************************************************************************/ *******************************************************************************/
@SafeVarargs
public static <T> T getFirstNonNull(T... ts) public static <T> T getFirstNonNull(T... ts)
{ {
if(ts == null || ts.length == 0) if(ts == null || ts.length == 0)

View File

@ -48,7 +48,11 @@ public class YamlUtils
{ {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
objectMapper.findAndRegisterModules(); objectMapper.findAndRegisterModules();
return (objectMapper.readValue(yaml, Map.class));
@SuppressWarnings("unchecked")
Map<String, Object> map = objectMapper.readValue(yaml, Map.class);
return map;
} }

View File

@ -86,7 +86,7 @@ public class AlphaNumericComparator implements Comparator<String>
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
if(INT_PATTERN.matcher(a).matches() && INT_PATTERN.matcher(b).matches()) if(INT_PATTERN.matcher(a).matches() && INT_PATTERN.matcher(b).matches())
{ {
int intsCompared = new Integer(a).compareTo(new Integer(b)); int intsCompared = Integer.valueOf(a).compareTo(Integer.valueOf(b));
if(intsCompared == TIE) if(intsCompared == TIE)
{ {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -119,7 +119,7 @@ public class AlphaNumericComparator implements Comparator<String>
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// if the ints compare as non-zero, return that comparison // // if the ints compare as non-zero, return that comparison //
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
int intPartCompared = new Integer(aIntPart).compareTo(new Integer(bIntPart)); int intPartCompared = Integer.valueOf(aIntPart).compareTo(Integer.valueOf(bIntPart));
if(intPartCompared != TIE) if(intPartCompared != TIE)
{ {
return (intPartCompared); return (intPartCompared);

View File

@ -26,7 +26,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
@SuppressWarnings({ "checkstyle:javadoc", "DanglingJavadoc" })
/******************************************************************************* /*******************************************************************************
** List.of is "great", but annoying because it makes unmodifiable lists... ** List.of is "great", but annoying because it makes unmodifiable lists...
** So, replace it with this, which returns ArrayLists, which "don't suck" ** So, replace it with this, which returns ArrayLists, which "don't suck"

View File

@ -27,7 +27,6 @@ import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
@SuppressWarnings({ "checkstyle:javadoc", "DanglingJavadoc" })
/******************************************************************************* /*******************************************************************************
** Map.of is "great", but annoying because it makes unmodifiable maps, and it ** Map.of is "great", but annoying because it makes unmodifiable maps, and it
** NPE's on nulls... So, replace it with this, which returns HashMaps (or maps ** NPE's on nulls... So, replace it with this, which returns HashMaps (or maps

View File

@ -87,7 +87,9 @@ public class MultiLevelMapHelper
{ {
try try
{ {
return (map.getClass().getConstructor().newInstance()); @SuppressWarnings("unchecked")
Map<K2, V> map1 = map.getClass().getConstructor().newInstance();
return map1;
} }
catch(Exception e) catch(Exception e)
{ {

View File

@ -174,7 +174,7 @@ class StandardScheduledExecutorTest extends BaseTest
@Override @Override
public void execute(RecordAutomationInput recordAutomationInput) throws QException public void execute(RecordAutomationInput recordAutomationInput) throws QException
{ {
sessionId = recordAutomationInput.getSession().getIdReference(); sessionId = QContext.getQSession().getIdReference();
} }
} }

View File

@ -99,7 +99,7 @@ class ChildRecordListRendererTest extends BaseTest
.getWidgetMetaData(); .getWidgetMetaData();
qInstance.addWidget(widget); qInstance.addWidget(widget);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1) new QRecord().withValue("id", 1)
)); ));
@ -130,12 +130,12 @@ class ChildRecordListRendererTest extends BaseTest
.getWidgetMetaData(); .getWidgetMetaData();
qInstance.addWidget(widget); qInstance.addWidget(widget);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1), new QRecord().withValue("id", 1),
new QRecord().withValue("id", 2) new QRecord().withValue("id", 2)
)); ));
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of(
new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2), new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2),
new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1), new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1),
new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found. new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found.

View File

@ -128,7 +128,7 @@ class ParentWidgetRendererTest extends BaseTest
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true); QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1) new QRecord().withValue("id", 1)
)); ));
@ -161,12 +161,12 @@ class ParentWidgetRendererTest extends BaseTest
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true); QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1), new QRecord().withValue("id", 1),
new QRecord().withValue("id", 2) new QRecord().withValue("id", 2)
)); ));
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of(
new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2), new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2),
new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1), new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1),
new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found. new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found.

View File

@ -109,7 +109,7 @@ class ProcessWidgetRendererTest extends BaseTest
.getWidgetMetaData(); .getWidgetMetaData();
qInstance.addWidget(widget); qInstance.addWidget(widget);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1) new QRecord().withValue("id", 1)
)); ));
@ -140,12 +140,12 @@ class ProcessWidgetRendererTest extends BaseTest
.getWidgetMetaData(); .getWidgetMetaData();
qInstance.addWidget(widget); qInstance.addWidget(widget);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1), new QRecord().withValue("id", 1),
new QRecord().withValue("id", 2) new QRecord().withValue("id", 2)
)); ));
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of(
new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2), new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2),
new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1), new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1),
new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found. new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found.

View File

@ -1,5 +1,22 @@
/* /*
* Copyright © 2022-2023. ColdTrack <contact@coldtrack.com>. All Rights Reserved. * QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets; package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;

View File

@ -1,5 +1,22 @@
/* /*
* Copyright © 2022-2023. ColdTrack <contact@coldtrack.com>. All Rights Reserved. * QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets; package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;

View File

@ -116,7 +116,7 @@ class USMapRendererTest extends BaseTest
.getWidgetMetaData(); .getWidgetMetaData();
qInstance.addWidget(widget); qInstance.addWidget(widget);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1) new QRecord().withValue("id", 1)
)); ));
@ -147,12 +147,12 @@ class USMapRendererTest extends BaseTest
.getWidgetMetaData(); .getWidgetMetaData();
qInstance.addWidget(widget); qInstance.addWidget(widget);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1), new QRecord().withValue("id", 1),
new QRecord().withValue("id", 2) new QRecord().withValue("id", 2)
)); ));
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of(
new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2), new QRecord().withValue("orderId", 1).withValue("sku", "ABC").withValue("lineNumber", 2),
new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1), new QRecord().withValue("orderId", 1).withValue("sku", "BCD").withValue("lineNumber", 1),
new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found. new QRecord().withValue("orderId", 2).withValue("sku", "XYZ") // should not be found.

View File

@ -67,7 +67,8 @@ class ProcessMetaDataActionTest extends BaseTest
@Test @Test
public void test_notFound() public void test_notFound()
{ {
assertThrows(QNotFoundException.class, () -> { assertThrows(QNotFoundException.class, () ->
{
ProcessMetaDataInput request = new ProcessMetaDataInput(); ProcessMetaDataInput request = new ProcessMetaDataInput();
request.setProcessName("willNotBeFound"); request.setProcessName("willNotBeFound");
new ProcessMetaDataAction().execute(request); new ProcessMetaDataAction().execute(request);

View File

@ -65,7 +65,8 @@ class TableMetaDataActionTest extends BaseTest
@Test @Test
public void test_notFound() public void test_notFound()
{ {
assertThrows(QUserFacingException.class, () -> { assertThrows(QUserFacingException.class, () ->
{
TableMetaDataInput request = new TableMetaDataInput(); TableMetaDataInput request = new TableMetaDataInput();
request.setTableName("willNotBeFound"); request.setTableName("willNotBeFound");
new TableMetaDataAction().execute(request); new TableMetaDataAction().execute(request);

View File

@ -51,16 +51,16 @@ public class RunProcessUpdateStepListTest extends BaseTest
{ {
private static final String PROCESS_NAME = RunProcessUpdateStepListTest.class.getSimpleName(); private static final String PROCESS_NAME = RunProcessUpdateStepListTest.class.getSimpleName();
private final static String STEP_START = "start"; private static final String STEP_START = "start";
private final static String STEP_A = "a"; private static final String STEP_A = "a";
private final static String STEP_B = "b"; private static final String STEP_B = "b";
private final static String STEP_C = "c"; private static final String STEP_C = "c";
private final static String STEP_1 = "1"; private static final String STEP_1 = "1";
private final static String STEP_2 = "2"; private static final String STEP_2 = "2";
private final static String STEP_3 = "3"; private static final String STEP_3 = "3";
private final static String STEP_END = "end"; private static final String STEP_END = "end";
private final static List<String> LETTERS_STEP_LIST = List.of( private static final List<String> LETTERS_STEP_LIST = List.of(
STEP_START, STEP_START,
STEP_A, STEP_A,
STEP_B, STEP_B,
@ -68,7 +68,7 @@ public class RunProcessUpdateStepListTest extends BaseTest
STEP_END STEP_END
); );
private final static List<String> NUMBERS_STEP_LIST = List.of( private static final List<String> NUMBERS_STEP_LIST = List.of(
STEP_START, STEP_START,
STEP_1, STEP_1,
STEP_2, STEP_2,

View File

@ -155,12 +155,12 @@ class ExportActionTest extends BaseTest
QInstance qInstance = QContext.getQInstance(); QInstance qInstance = QContext.getQInstance();
QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true); QContext.getQSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_TYPE_STORE_ALL_ACCESS, true);
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_ORDER), List.of(
new QRecord().withValue("id", 1).withValue("orderNo", "ORD1").withValue("storeId", 1), new QRecord().withValue("id", 1).withValue("orderNo", "ORD1").withValue("storeId", 1),
new QRecord().withValue("id", 2).withValue("orderNo", "ORD2").withValue("storeId", 1) new QRecord().withValue("id", 2).withValue("orderNo", "ORD2").withValue("storeId", 1)
)); ));
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_LINE_ITEM), List.of(
new QRecord().withValue("id", 1).withValue("orderId", 1).withValue("sku", "A").withValue("quantity", 10), new QRecord().withValue("id", 1).withValue("orderId", 1).withValue("sku", "A").withValue("quantity", 10),
new QRecord().withValue("id", 2).withValue("orderId", 1).withValue("sku", "B").withValue("quantity", 15), new QRecord().withValue("id", 2).withValue("orderId", 1).withValue("sku", "B").withValue("quantity", 15),
new QRecord().withValue("id", 3).withValue("orderId", 2).withValue("sku", "A").withValue("quantity", 20) new QRecord().withValue("id", 3).withValue("orderId", 2).withValue("sku", "A").withValue("quantity", 20)

View File

@ -562,7 +562,7 @@ public class GenerateReportActionTest extends BaseTest
*******************************************************************************/ *******************************************************************************/
public static void insertPersonRecords(QInstance qInstance) throws QException public static void insertPersonRecords(QInstance qInstance) throws QException
{ {
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of( TestUtils.insertRecords(qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
new PersonQRecord().withFirstName("Darin").withLastName("Jonson").withBirthDate(LocalDate.of(1980, Month.JANUARY, 31)).withNoOfShoes(null).withHomeStateId(1).withPrice(null).withCost(new BigDecimal("0.50")), // wrong last initial new PersonQRecord().withFirstName("Darin").withLastName("Jonson").withBirthDate(LocalDate.of(1980, Month.JANUARY, 31)).withNoOfShoes(null).withHomeStateId(1).withPrice(null).withCost(new BigDecimal("0.50")), // wrong last initial
new PersonQRecord().withFirstName("Darin").withLastName("Jones").withBirthDate(LocalDate.of(1980, Month.JANUARY, 31)).withNoOfShoes(3).withHomeStateId(1).withPrice(new BigDecimal("1.00")).withCost(new BigDecimal("0.50")), // wrong last initial new PersonQRecord().withFirstName("Darin").withLastName("Jones").withBirthDate(LocalDate.of(1980, Month.JANUARY, 31)).withNoOfShoes(3).withHomeStateId(1).withPrice(new BigDecimal("1.00")).withCost(new BigDecimal("0.50")), // wrong last initial
new PersonQRecord().withFirstName("Darin").withLastName("Kelly").withBirthDate(LocalDate.of(1979, Month.DECEMBER, 30)).withNoOfShoes(4).withHomeStateId(1).withPrice(new BigDecimal("1.20")).withCost(new BigDecimal("0.50")), // bad birthdate new PersonQRecord().withFirstName("Darin").withLastName("Kelly").withBirthDate(LocalDate.of(1979, Month.DECEMBER, 30)).withNoOfShoes(4).withHomeStateId(1).withPrice(new BigDecimal("1.20")).withCost(new BigDecimal("0.50")), // bad birthdate

Some files were not shown because too many files have changed in this diff Show More