mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Merged dev into feature/meta-data-loaders
This commit is contained in:
@ -127,14 +127,9 @@ commands:
|
|||||||
command: |
|
command: |
|
||||||
cd docs
|
cd docs
|
||||||
asciidoctor -a docinfo=shared index.adoc
|
asciidoctor -a docinfo=shared index.adoc
|
||||||
|
- store_artifacts:
|
||||||
upload_docs_site:
|
path: docs/index.html
|
||||||
steps:
|
when: always
|
||||||
- run:
|
|
||||||
name: scp html to justinsgotskinnylegs.com
|
|
||||||
command: |
|
|
||||||
cd docs
|
|
||||||
scp index.html dkelkhoff@45.79.44.221:/mnt/first-volume/dkelkhoff/nginx/html/justinsgotskinnylegs.com/qqq-docs.html
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
mvn_test:
|
mvn_test:
|
||||||
@ -159,7 +154,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- install_asciidoctor
|
- install_asciidoctor
|
||||||
- run_asciidoctor
|
- run_asciidoctor
|
||||||
- upload_docs_site
|
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
test_only:
|
test_only:
|
||||||
|
@ -147,8 +147,8 @@ public class BackendMetaDataProvider
|
|||||||
As the size of your application grows, if you're doing per-object meta-data providers, you may find it
|
As the size of your application grows, if you're doing per-object meta-data providers, you may find it
|
||||||
burdensome, when adding a new object to your instance, to have to write code for it in two places -
|
burdensome, when adding a new object to your instance, to have to write code for it in two places -
|
||||||
that is - a new class to produce that meta-data object, AND a single line of code to add that object
|
that is - a new class to produce that meta-data object, AND a single line of code to add that object
|
||||||
to your `QInstance`. As such, a mechanism to avoid that line-of-code to add the object to the
|
to your `QInstance`. As such, a mechanism exists to let you avoid that line-of-code for adding the object
|
||||||
`QInstance` exists.
|
to the `QInstance`.
|
||||||
|
|
||||||
This mechanism involves adding the `MetaDataProducerInterface` to all of your classes that produce a
|
This mechanism involves adding the `MetaDataProducerInterface` to all of your classes that produce a
|
||||||
meta-data object. This interface is generic, with a type parameter that will typically be the type of
|
meta-data object. This interface is generic, with a type parameter that will typically be the type of
|
||||||
@ -204,7 +204,7 @@ that are all related, and it's only a handful of lines of code for each one, may
|
|||||||
produce them all in the same class. Or maybe when you define a table, you'd like to define its
|
produce them all in the same class. Or maybe when you define a table, you'd like to define its
|
||||||
joins and widgets at the same time.
|
joins and widgets at the same time.
|
||||||
|
|
||||||
This approach can be accomplished by making your `MetaDataProducerInterface`'s type argument by
|
This approach can be accomplished by making the type argument for your `MetaDataProducerInterface` be
|
||||||
`MetaDataProducerMultiOutput` - a simple class that just wraps a list of other `MetaDataProducerOutput`
|
`MetaDataProducerMultiOutput` - a simple class that just wraps a list of other `MetaDataProducerOutput`
|
||||||
objects.
|
objects.
|
||||||
|
|
||||||
@ -238,12 +238,13 @@ be specified in their meta-data object.
|
|||||||
At the same time, if you're writing any custom code in your QQQ application
|
At the same time, if you're writing any custom code in your QQQ application
|
||||||
(e.g., any processes or table customizers), where you're working with records from tables, you may
|
(e.g., any processes or table customizers), where you're working with records from tables, you may
|
||||||
prefer being able to work with entity beans (e.g., java classes with typed getter & setter methods),
|
prefer being able to work with entity beans (e.g., java classes with typed getter & setter methods),
|
||||||
rather than the default object type that QQQ's ORM actions return, the `QRecord`, which carriers all
|
rather than the default object type that QQQ's ORM actions return, the `QRecord`, which carries all
|
||||||
of its values in a `Map`. QQQ has a mechanism for dealing with this - in the form of the `QRecordEntity`
|
of its values in a `Map` (where you don't get compile-time checks of field names or data types).
|
||||||
class.
|
QQQ has a mechanism for dealing with this - in the form of the `QRecordEntity` class.
|
||||||
|
|
||||||
So - if you want to build your application using entity beans (which is recommended, for the compile-time
|
So - if you want to build your application using entity beans (which is recommended, for the compile-time
|
||||||
safety that they provide in custom code), you will be writing a `QRecordEntity` class, which will look like:
|
safety that they provide in custom code), you will be writing a `QRecordEntity` class for each of your tables,
|
||||||
|
which will look like:
|
||||||
|
|
||||||
[source,java]
|
[source,java]
|
||||||
.QRecordEntity example
|
.QRecordEntity example
|
||||||
@ -280,7 +281,7 @@ public QTableMetaData produce(QInstance qInstance) throws QExcpetion
|
|||||||
----
|
----
|
||||||
|
|
||||||
That `withFieldsFromEntity` call is one of the biggest benefits of this technique. It allows you to avoid defining
|
That `withFieldsFromEntity` call is one of the biggest benefits of this technique. It allows you to avoid defining
|
||||||
all of the field in you table in two place (the entity and the table meta-data).
|
all of the fields in you table in two places (the entity and the table meta-data).
|
||||||
|
|
||||||
== MetaData Producing Annotations for Entities
|
== MetaData Producing Annotations for Entities
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ public class AsyncRecordPipeLoop
|
|||||||
|
|
||||||
if(recordCount > 0)
|
if(recordCount > 0)
|
||||||
{
|
{
|
||||||
LOG.info("End of job summary", logPair("recordCount", recordCount), logPair("jobName", jobName), logPair("millis", endTime - jobStartTime), logPair("recordsPerSecond", 1000d * (recordCount / (.001d + (endTime - jobStartTime)))));
|
LOG.debug("End of job summary", logPair("recordCount", recordCount), logPair("jobName", jobName), logPair("millis", endTime - jobStartTime), logPair("recordsPerSecond", 1000d * (recordCount / (.001d + (endTime - jobStartTime)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (recordCount);
|
return (recordCount);
|
||||||
|
@ -120,6 +120,16 @@ public enum QFieldType
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean isTemporal()
|
||||||
|
{
|
||||||
|
return this == QFieldType.DATE || this == QFieldType.DATE_TIME || this == QFieldType.TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -189,7 +189,7 @@ public class StreamedETLExecuteStep extends BaseStreamedETLStep implements Backe
|
|||||||
|
|
||||||
if(recordCount > 0)
|
if(recordCount > 0)
|
||||||
{
|
{
|
||||||
LOG.info("Processed [" + recordCount + "] records.");
|
LOG.debug("Processed [" + recordCount + "] records.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -223,7 +223,7 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt
|
|||||||
{
|
{
|
||||||
if(CollectionUtils.nullSafeIsEmpty(runBackendStepInput.getRecords()))
|
if(CollectionUtils.nullSafeIsEmpty(runBackendStepInput.getRecords()))
|
||||||
{
|
{
|
||||||
LOG.info("No input records were found.");
|
LOG.debug("No input records were found.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +159,10 @@ public class RDBMSAggregateAction extends AbstractRDBMSAction implements Aggrega
|
|||||||
{
|
{
|
||||||
fieldType = QFieldType.DECIMAL;
|
fieldType = QFieldType.DECIMAL;
|
||||||
}
|
}
|
||||||
|
else if(field.getType().isTemporal() && (aggregate.getOperator().equals(AggregateOperator.COUNT)) || aggregate.getOperator().equals(AggregateOperator.COUNT_DISTINCT))
|
||||||
|
{
|
||||||
|
fieldType = QFieldType.INTEGER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fieldType != null)
|
if(fieldType != null)
|
||||||
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
|||||||
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
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;
|
||||||
@ -42,13 +43,16 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
|||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
||||||
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.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
@ -83,20 +87,56 @@ public class RDBMSAggregateActionTest extends RDBMSActionTest
|
|||||||
Aggregate averageOfDaysWorked = new Aggregate("daysWorked", AggregateOperator.AVG);
|
Aggregate averageOfDaysWorked = new Aggregate("daysWorked", AggregateOperator.AVG);
|
||||||
Aggregate maxAnnualSalary = new Aggregate("annualSalary", AggregateOperator.MAX);
|
Aggregate maxAnnualSalary = new Aggregate("annualSalary", AggregateOperator.MAX);
|
||||||
Aggregate minFirstName = new Aggregate("firstName", AggregateOperator.MIN);
|
Aggregate minFirstName = new Aggregate("firstName", AggregateOperator.MIN);
|
||||||
|
Aggregate countOfBirthDate = new Aggregate("birthDate", AggregateOperator.COUNT);
|
||||||
aggregateInput.withAggregate(countOfId);
|
aggregateInput.withAggregate(countOfId);
|
||||||
aggregateInput.withAggregate(sumOfId);
|
aggregateInput.withAggregate(sumOfId);
|
||||||
aggregateInput.withAggregate(averageOfDaysWorked);
|
aggregateInput.withAggregate(averageOfDaysWorked);
|
||||||
aggregateInput.withAggregate(maxAnnualSalary);
|
aggregateInput.withAggregate(maxAnnualSalary);
|
||||||
aggregateInput.withAggregate(minFirstName);
|
aggregateInput.withAggregate(minFirstName);
|
||||||
|
aggregateInput.withAggregate(countOfBirthDate);
|
||||||
|
|
||||||
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
||||||
|
|
||||||
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
||||||
Assertions.assertEquals(5, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(5, aggregateResult.getAggregateValue(countOfId));
|
||||||
Assertions.assertEquals(15, aggregateResult.getAggregateValue(sumOfId));
|
assertEquals(15, aggregateResult.getAggregateValue(sumOfId));
|
||||||
Assertions.assertEquals(new BigDecimal("96.4"), aggregateResult.getAggregateValue(averageOfDaysWorked));
|
assertEquals(new BigDecimal("96.4"), aggregateResult.getAggregateValue(averageOfDaysWorked));
|
||||||
Assertions.assertEquals(new BigDecimal("1000000.00"), aggregateResult.getAggregateValue(maxAnnualSalary));
|
assertEquals(new BigDecimal("1000000.00"), aggregateResult.getAggregateValue(maxAnnualSalary));
|
||||||
Assertions.assertEquals("Darin", aggregateResult.getAggregateValue(minFirstName));
|
assertEquals("Darin", aggregateResult.getAggregateValue(minFirstName));
|
||||||
|
assertEquals(4, aggregateResult.getAggregateValue(countOfBirthDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
@Disabled("Interesting to see effects of all operators on all types, but failures are expected (e.g., avg(string), so not for CI.")
|
||||||
|
void testOperatorsCrossTypes()
|
||||||
|
{
|
||||||
|
List<String> failures = new ArrayList<>();
|
||||||
|
for(QFieldMetaData field : QContext.getQInstance().getTable(TestUtils.TABLE_NAME_PERSON).getFields().values())
|
||||||
|
{
|
||||||
|
for(AggregateOperator aggregateOperator : AggregateOperator.values())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AggregateInput aggregateInput = initAggregateRequest();
|
||||||
|
Aggregate aggregate = new Aggregate(field.getName(), aggregateOperator);
|
||||||
|
aggregateInput.withAggregate(aggregate);
|
||||||
|
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
||||||
|
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
||||||
|
assertNotNull(aggregateResult.getAggregateValue(aggregate));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
failures.add(ExceptionUtils.getRootException(e).getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
failures.forEach(System.out::println);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -123,11 +163,11 @@ public class RDBMSAggregateActionTest extends RDBMSActionTest
|
|||||||
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
||||||
|
|
||||||
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
||||||
Assertions.assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
||||||
Assertions.assertEquals(5, aggregateResult.getAggregateValue(sumOfId));
|
assertEquals(5, aggregateResult.getAggregateValue(sumOfId));
|
||||||
Assertions.assertEquals(new BigDecimal("62.0"), aggregateResult.getAggregateValue(averageOfDaysWorked));
|
assertEquals(new BigDecimal("62.0"), aggregateResult.getAggregateValue(averageOfDaysWorked));
|
||||||
Assertions.assertEquals(new BigDecimal("26000.00"), aggregateResult.getAggregateValue(maxAnnualSalary));
|
assertEquals(new BigDecimal("26000.00"), aggregateResult.getAggregateValue(maxAnnualSalary));
|
||||||
Assertions.assertEquals("James", aggregateResult.getAggregateValue(minFirstName));
|
assertEquals("James", aggregateResult.getAggregateValue(minFirstName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -156,15 +196,15 @@ public class RDBMSAggregateActionTest extends RDBMSActionTest
|
|||||||
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
||||||
{
|
{
|
||||||
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
||||||
Assertions.assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
||||||
Assertions.assertEquals(17, aggregateResult.getAggregateValue(sumOfDaysWorked));
|
assertEquals(17, aggregateResult.getAggregateValue(sumOfDaysWorked));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
AggregateResult aggregateResult = aggregateOutput.getResults().get(1);
|
AggregateResult aggregateResult = aggregateOutput.getResults().get(1);
|
||||||
Assertions.assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals(4, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(4, aggregateResult.getAggregateValue(countOfId));
|
||||||
Assertions.assertEquals(11364, aggregateResult.getAggregateValue(sumOfDaysWorked));
|
assertEquals(11364, aggregateResult.getAggregateValue(sumOfDaysWorked));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,29 +241,29 @@ public class RDBMSAggregateActionTest extends RDBMSActionTest
|
|||||||
AggregateResult aggregateResult;
|
AggregateResult aggregateResult;
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals("Donny", aggregateResult.getGroupByValue(firstNameGroupBy));
|
assertEquals("Donny", aggregateResult.getGroupByValue(firstNameGroupBy));
|
||||||
Assertions.assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals("Tim", aggregateResult.getGroupByValue(firstNameGroupBy));
|
assertEquals("Tim", aggregateResult.getGroupByValue(firstNameGroupBy));
|
||||||
Assertions.assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals("Aaron", aggregateResult.getGroupByValue(firstNameGroupBy));
|
assertEquals("Aaron", aggregateResult.getGroupByValue(firstNameGroupBy));
|
||||||
Assertions.assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals("Darin", aggregateResult.getGroupByValue(firstNameGroupBy));
|
assertEquals("Darin", aggregateResult.getGroupByValue(firstNameGroupBy));
|
||||||
Assertions.assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals("Trevor", aggregateResult.getGroupByValue(firstNameGroupBy));
|
assertEquals("Trevor", aggregateResult.getGroupByValue(firstNameGroupBy));
|
||||||
Assertions.assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -255,24 +295,24 @@ public class RDBMSAggregateActionTest extends RDBMSActionTest
|
|||||||
AggregateResult aggregateResult;
|
AggregateResult aggregateResult;
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Kelkhoff", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals(4, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(4, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Richardson", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Richardson", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Maes", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Maes", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Samples", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Samples", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(1, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
aggregateResult = iterator.next();
|
aggregateResult = iterator.next();
|
||||||
Assertions.assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
assertEquals("Chamberlain", aggregateResult.getGroupByValue(lastNameGroupBy));
|
||||||
Assertions.assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(2, aggregateResult.getAggregateValue(countOfId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -293,7 +333,7 @@ public class RDBMSAggregateActionTest extends RDBMSActionTest
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
AggregateOutput aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
||||||
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
AggregateResult aggregateResult = aggregateOutput.getResults().get(0);
|
||||||
Assertions.assertEquals(0, aggregateResult.getAggregateValue(countOfId));
|
assertEquals(0, aggregateResult.getAggregateValue(countOfId));
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// but re-run w/ a group-by -- then, if no rows are found, there are 0 result objects. //
|
// but re-run w/ a group-by -- then, if no rows are found, there are 0 result objects. //
|
||||||
@ -324,12 +364,12 @@ public class RDBMSAggregateActionTest extends RDBMSActionTest
|
|||||||
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_STORE_ALL_ACCESS, true));
|
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_STORE_ALL_ACCESS, true));
|
||||||
aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
||||||
aggregateResult = aggregateOutput.getResults().get(0);
|
aggregateResult = aggregateOutput.getResults().get(0);
|
||||||
Assertions.assertEquals(43, aggregateResult.getAggregateValue(sumOfQuantity));
|
assertEquals(43, aggregateResult.getAggregateValue(sumOfQuantity));
|
||||||
|
|
||||||
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 1));
|
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.TABLE_NAME_STORE, 1));
|
||||||
aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
aggregateOutput = new RDBMSAggregateAction().execute(aggregateInput);
|
||||||
aggregateResult = aggregateOutput.getResults().get(0);
|
aggregateResult = aggregateOutput.getResults().get(0);
|
||||||
Assertions.assertEquals(33, aggregateResult.getAggregateValue(sumOfQuantity));
|
assertEquals(33, aggregateResult.getAggregateValue(sumOfQuantity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import com.kingsrook.qqq.middleware.javalin.specs.v1.MiddlewareVersionV1;
|
|||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
import org.apache.commons.lang.BooleanUtils;
|
import org.apache.commons.lang.BooleanUtils;
|
||||||
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -102,17 +103,23 @@ public class QApplicationJavalinServer
|
|||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// If you have any assets to add to the web server (e.g., logos, icons) place them at //
|
// If you have any assets to add to the web server (e.g., logos, icons) place them at //
|
||||||
// src/main/resources/material-dashboard-overlay (or a directory of your choice //
|
// src/main/resources/material-dashboard-overlay //
|
||||||
// under src/main/resources) and use this line of code to tell javalin about it. //
|
// we'll use the same check that javalin (jetty?) internally uses to see if this //
|
||||||
// Make sure to add your app-specific directory to the javalin config before the core //
|
// directory exists - because if it doesn't, then it'll fail to start the server... //
|
||||||
// material-dashboard directory, so in case the same file exists in both (e.g., //
|
// note that that Resource object is auto-closable, hence the try-with-resources //
|
||||||
// favicon.png), the app-specific one will be used. //
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
try(Resource resource = Resource.newClassPathResource("/material-dashboard-overlay"))
|
||||||
|
{
|
||||||
|
if(resource !=null)
|
||||||
|
{
|
||||||
config.staticFiles.add("/material-dashboard-overlay");
|
config.staticFiles.add("/material-dashboard-overlay");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
// tell javalin where to find material-dashboard static web assets //
|
// tell javalin where to find material-dashboard static web assets //
|
||||||
/////////////////////////////////////////////////////////////////////
|
// in this case, this path is coming from the qqq-frontend-material-dashboard jar //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
config.staticFiles.add("/material-dashboard");
|
config.staticFiles.add("/material-dashboard");
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.kingsrook.qqq</groupId>
|
<groupId>com.kingsrook.qqq</groupId>
|
||||||
<artifactId>qqq-frontend-material-dashboard</artifactId>
|
<artifactId>qqq-frontend-material-dashboard</artifactId>
|
||||||
<version>0.20.0</version>
|
<version>0.24.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
@ -119,12 +119,16 @@
|
|||||||
<descriptorRefs>
|
<descriptorRefs>
|
||||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
</descriptorRefs>
|
</descriptorRefs>
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<mainClass>com.kingsrook.sampleapp.SampleCli</mainClass>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
|
@ -23,10 +23,8 @@ package com.kingsrook.sampleapp;
|
|||||||
|
|
||||||
|
|
||||||
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.middleware.javalin.QApplicationJavalinServer;
|
||||||
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
|
|
||||||
import com.kingsrook.sampleapp.metadata.SampleMetaDataProvider;
|
import com.kingsrook.sampleapp.metadata.SampleMetaDataProvider;
|
||||||
import io.javalin.Javalin;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -36,12 +34,6 @@ public class SampleJavalinServer
|
|||||||
{
|
{
|
||||||
private static final QLogger LOG = QLogger.getLogger(SampleJavalinServer.class);
|
private static final QLogger LOG = QLogger.getLogger(SampleJavalinServer.class);
|
||||||
|
|
||||||
private static final int PORT = 8000;
|
|
||||||
|
|
||||||
private QInstance qInstance;
|
|
||||||
|
|
||||||
private Javalin javalinService;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -49,7 +41,7 @@ public class SampleJavalinServer
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
new SampleJavalinServer().startJavalinServer();
|
new SampleJavalinServer().start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -57,38 +49,11 @@ public class SampleJavalinServer
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void startJavalinServer()
|
public void start()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
qInstance = SampleMetaDataProvider.defineInstance();
|
new QApplicationJavalinServer(new SampleMetaDataProvider()).start();
|
||||||
|
|
||||||
QJavalinImplementation qJavalinImplementation = new QJavalinImplementation(qInstance);
|
|
||||||
javalinService = Javalin.create(config ->
|
|
||||||
{
|
|
||||||
config.router.apiBuilder(qJavalinImplementation.getRoutes());
|
|
||||||
// todo - not all?
|
|
||||||
config.bundledPlugins.enableCors(cors -> cors.addRule(corsRule -> corsRule.anyHost()));
|
|
||||||
}).start(PORT);
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
|
||||||
// set the server to hot-swap the q instance before all routes //
|
|
||||||
/////////////////////////////////////////////////////////////////
|
|
||||||
QJavalinImplementation.setQInstanceHotSwapSupplier(() ->
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (SampleMetaDataProvider.defineInstance());
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
LOG.warn("Error hot-swapping meta data", e);
|
|
||||||
return (null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
javalinService.before(QJavalinImplementation::hotSwapQInstance);
|
|
||||||
|
|
||||||
javalinService.after(ctx -> ctx.res().setHeader("Access-Control-Allow-Origin", "http://localhost:3000"));
|
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
@ -96,16 +61,4 @@ public class SampleJavalinServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public void stopJavalinServer()
|
|
||||||
{
|
|
||||||
if(javalinService != null)
|
|
||||||
{
|
|
||||||
javalinService.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.QuickSightChartR
|
|||||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||||
|
import com.kingsrook.qqq.backend.core.instances.AbstractQQQApplication;
|
||||||
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
|
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
|
||||||
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
|
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||||
@ -78,7 +79,7 @@ import com.kingsrook.sampleapp.processes.clonepeople.ClonePeopleTransformStep;
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public class SampleMetaDataProvider
|
public class SampleMetaDataProvider extends AbstractQQQApplication
|
||||||
{
|
{
|
||||||
public static boolean USE_MYSQL = true;
|
public static boolean USE_MYSQL = true;
|
||||||
|
|
||||||
@ -108,6 +109,17 @@ public class SampleMetaDataProvider
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
@Override
|
||||||
|
public QInstance defineQInstance() throws QException
|
||||||
|
{
|
||||||
|
return (defineInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -145,7 +157,7 @@ public class SampleMetaDataProvider
|
|||||||
private static void defineBranding(QInstance qInstance)
|
private static void defineBranding(QInstance qInstance)
|
||||||
{
|
{
|
||||||
qInstance.setBranding(new QBrandingMetaData()
|
qInstance.setBranding(new QBrandingMetaData()
|
||||||
.withLogo("/kr-logo.png")
|
.withLogo("/samples-logo.png")
|
||||||
.withIcon("/kr-icon.png"));
|
.withIcon("/kr-icon.png"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 129 KiB |
@ -38,8 +38,7 @@ class SampleJavalinServerTest
|
|||||||
void testStartStop()
|
void testStartStop()
|
||||||
{
|
{
|
||||||
SampleJavalinServer sampleJavalinServer = new SampleJavalinServer();
|
SampleJavalinServer sampleJavalinServer = new SampleJavalinServer();
|
||||||
sampleJavalinServer.startJavalinServer();
|
sampleJavalinServer.start();
|
||||||
sampleJavalinServer.stopJavalinServer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user