From 3b80c5cd3f7d4fe145d241f8619d1c3d18f39f2a Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Wed, 27 Mar 2024 20:12:16 -0500 Subject: [PATCH] CE-881 - Initial test updates for this story (saved reports, excel pivots) --- .../actions/reporting/ExportActionTest.java | 34 ++- .../reporting/GenerateReportActionTest.java | 280 ++++++++++++++---- .../templates/ConvertHtmlToPdfActionTest.java | 5 +- .../DynamicDefaultValueBehaviorTest.java | 44 +++ .../reports/BasicRunReportProcessTest.java | 2 +- .../backend/core/testutils/PersonQRecord.java | 8 + 6 files changed, 305 insertions(+), 68 deletions(-) diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportActionTest.java index 9ff5f7de..ff089474 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportActionTest.java @@ -36,6 +36,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.model.actions.reporting.ExportInput; import com.kingsrook.qqq.backend.core.model.actions.reporting.ExportOutput; +import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter; import com.kingsrook.qqq.backend.core.model.data.QRecord; @@ -43,6 +44,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; +import com.kingsrook.qqq.backend.core.utils.LocalMacDevUtils; import com.kingsrook.qqq.backend.core.utils.TestUtils; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; @@ -118,6 +120,26 @@ class ExportActionTest extends BaseTest runReport(recordCount, filename, ReportFormat.XLSX, true); File file = new File(filename); + LocalMacDevUtils.openFile(file.getAbsolutePath()); + + assertTrue(file.delete()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void testExcelPOI() throws Exception + { + int recordCount = 1000; + String filename = "/tmp/ReportActionTest-POI.xlsx"; + + runReport(recordCount, filename, ReportFormat.XLSX, true); + + File file = new File(filename); + LocalMacDevUtils.openFile(file.getAbsolutePath()); assertTrue(file.delete()); } @@ -147,9 +169,10 @@ class ExportActionTest extends BaseTest ExportInput exportInput = new ExportInput(); exportInput.setTableName(TestUtils.TABLE_NAME_ORDER); - exportInput.setReportFormat(ReportFormat.CSV); ByteArrayOutputStream reportOutputStream = new ByteArrayOutputStream(); - exportInput.setReportOutputStream(reportOutputStream); + exportInput.setReportDestination(new ReportDestination() + .withReportFormat(ReportFormat.CSV) + .withReportOutputStream(reportOutputStream)); exportInput.setQueryFilter(new QQueryFilter()); exportInput.setFieldNames(List.of("id", "orderNo", "storeId", "orderLine.id", "orderLine.sku", "orderLine.quantity")); // exportInput.setFieldNames(List.of("id", "orderNo", "storeId")); @@ -197,8 +220,7 @@ class ExportActionTest extends BaseTest exportInput.setTableName("person"); QTableMetaData table = exportInput.getTable(); - exportInput.setReportFormat(reportFormat); - exportInput.setReportOutputStream(outputStream); + exportInput.setReportDestination(new ReportDestination().withReportFormat(reportFormat).withReportOutputStream(outputStream)); exportInput.setQueryFilter(new QQueryFilter()); exportInput.setLimit(recordCount); @@ -243,7 +265,7 @@ class ExportActionTest extends BaseTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // use xlsx, which has a max-rows limit, to verify that code runs, but doesn't throw when there aren't too many rows // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - exportInput.setReportFormat(ReportFormat.XLSX); + exportInput.setReportDestination(new ReportDestination().withReportFormat(ReportFormat.XLSX)); new ExportAction().preExecute(exportInput); @@ -278,7 +300,7 @@ class ExportActionTest extends BaseTest //////////////////////////////////////////////////////////////// // use xlsx, which has a max-cols limit, to verify that code. // //////////////////////////////////////////////////////////////// - exportInput.setReportFormat(ReportFormat.XLSX); + exportInput.setReportDestination(new ReportDestination().withReportFormat(ReportFormat.XLSX)); assertThrows(QUserFacingException.class, () -> { diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java index 590d96e6..fca34aa3 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportActionTest.java @@ -23,19 +23,27 @@ package com.kingsrook.qqq.backend.core.actions.reporting; import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDate; import java.time.Month; +import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.kingsrook.qqq.backend.core.BaseTest; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput; +import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableDefinition; +import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableFunction; +import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableGroupBy; +import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableValue; 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.QFilterOrderBy; @@ -51,7 +59,14 @@ import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportView; import com.kingsrook.qqq.backend.core.model.metadata.reporting.ReportType; import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore; import com.kingsrook.qqq.backend.core.testutils.PersonQRecord; +import com.kingsrook.qqq.backend.core.utils.LocalMacDevUtils; import com.kingsrook.qqq.backend.core.utils.TestUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.usermodel.XSSFPivotTable; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -85,10 +100,10 @@ public class GenerateReportActionTest extends BaseTest ** *******************************************************************************/ @Test - void testPivot1() throws QException + void testSummary1() throws QException { QInstance qInstance = QContext.getQInstance(); - qInstance.addReport(definePersonShoesPivotReport(true)); + qInstance.addReport(definePersonShoesSummaryReport(true)); insertPersonRecords(qInstance); runReport(qInstance, Map.of("startDate", LocalDate.of(1980, Month.JANUARY, 1), "endDate", LocalDate.of(1980, Month.DECEMBER, 31))); @@ -140,10 +155,10 @@ public class GenerateReportActionTest extends BaseTest ** *******************************************************************************/ @Test - void testPivot2() throws QException + void testSummary2() throws QException { QInstance qInstance = QContext.getQInstance(); - QReportMetaData report = definePersonShoesPivotReport(false); + QReportMetaData report = definePersonShoesSummaryReport(false); ////////////////////////////////////////////// // change from the default to sort reversed // @@ -172,10 +187,10 @@ public class GenerateReportActionTest extends BaseTest ** *******************************************************************************/ @Test - void testPivot3() throws QException + void testSummary3() throws QException { QInstance qInstance = QContext.getQInstance(); - QReportMetaData report = definePersonShoesPivotReport(false); + QReportMetaData report = definePersonShoesSummaryReport(false); ////////////////////////////////////////////////////////////////////////////////////////////// // remove the filters, change to sort by personCount (to get some ties), then sumPrice desc // @@ -224,16 +239,16 @@ public class GenerateReportActionTest extends BaseTest ** *******************************************************************************/ @Test - void testPivot4() throws QException + void testSummary4() throws QException { QInstance qInstance = QContext.getQInstance(); - QReportMetaData report = definePersonShoesPivotReport(false); + QReportMetaData report = definePersonShoesSummaryReport(false); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // remove the filter, change to have 2 pivot columns - homeStateId and lastName - we should get no roll-up like this. // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// report.getDataSources().get(0).getQueryFilter().setCriteria(null); - report.getViews().get(0).setPivotFields(List.of( + report.getViews().get(0).setSummaryFields(List.of( "homeStateId", "lastName" )); @@ -282,16 +297,16 @@ public class GenerateReportActionTest extends BaseTest ** *******************************************************************************/ @Test - void testPivot5() throws QException + void testSummary5() throws QException { QInstance qInstance = QContext.getQInstance(); - QReportMetaData report = definePersonShoesPivotReport(false); + QReportMetaData report = definePersonShoesSummaryReport(false); ///////////////////////////////////////////////////////////////////////////////////// // remove the filter, and just pivot on homeStateId - should aggregate differently // ///////////////////////////////////////////////////////////////////////////////////// report.getDataSources().get(0).getQueryFilter().setCriteria(null); - report.getViews().get(0).setPivotFields(List.of("homeStateId")); + report.getViews().get(0).setSummaryFields(List.of("homeStateId")); qInstance.addReport(report); insertPersonRecords(qInstance); runReport(qInstance, Map.of("startDate", LocalDate.now(), "endDate", LocalDate.now())); @@ -322,13 +337,12 @@ public class GenerateReportActionTest extends BaseTest try(FileOutputStream fileOutputStream = new FileOutputStream(name)) { QInstance qInstance = QContext.getQInstance(); - qInstance.addReport(definePersonShoesPivotReport(true)); + qInstance.addReport(definePersonShoesSummaryReport(true)); insertPersonRecords(qInstance); ReportInput reportInput = new ReportInput(); reportInput.setReportName(REPORT_NAME); - reportInput.setReportFormat(ReportFormat.CSV); - reportInput.setReportOutputStream(fileOutputStream); + reportInput.setReportDestination(new ReportDestination().withReportFormat(ReportFormat.CSV).withReportOutputStream(fileOutputStream)); reportInput.setInputValues(Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now())); new GenerateReportAction().execute(reportInput); System.out.println("Wrote File: " + name); @@ -341,27 +355,122 @@ public class GenerateReportActionTest extends BaseTest ** *******************************************************************************/ @Test - void runToXlsx() throws Exception + void runSummaryToXlsx() throws Exception { - String name = "/tmp/report.xlsx"; + ReportFormat format = ReportFormat.XLSX; + String name = "/tmp/report-" + format + ".xlsx"; try(FileOutputStream fileOutputStream = new FileOutputStream(name)) { QInstance qInstance = QContext.getQInstance(); - qInstance.addReport(definePersonShoesPivotReport(true)); + qInstance.addReport(definePersonShoesSummaryReport(true)); insertPersonRecords(qInstance); ReportInput reportInput = new ReportInput(); reportInput.setReportName(REPORT_NAME); - reportInput.setReportFormat(ReportFormat.XLSX); - reportInput.setReportOutputStream(fileOutputStream); + reportInput.setReportDestination(new ReportDestination().withReportFormat(format).withReportOutputStream(fileOutputStream)); reportInput.setInputValues(Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now())); new GenerateReportAction().execute(reportInput); System.out.println("Wrote File: " + name); + + LocalMacDevUtils.openFile(name); } } + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void runTableToXlsx() throws Exception + { + ReportFormat format = ReportFormat.XLSX; + String name = "/tmp/report-" + format + ".xlsx"; + try(FileOutputStream fileOutputStream = new FileOutputStream(name)) + { + QInstance qInstance = QContext.getQInstance(); + qInstance.addReport(defineTableOnlyReport()); + insertPersonRecords(qInstance); + + ReportInput reportInput = new ReportInput(); + reportInput.setReportName(REPORT_NAME); + reportInput.setReportDestination(new ReportDestination().withReportFormat(format).withReportOutputStream(fileOutputStream)); + reportInput.setInputValues(Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now())); + new GenerateReportAction().execute(reportInput); + System.out.println("Wrote File: " + name); + + LocalMacDevUtils.openFile(name); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void runPivotToXlsx() throws Exception + { + String name = "/tmp/pivot-test.xlsx"; + try(FileOutputStream fileOutputStream = new FileOutputStream(name)) + { + QInstance qInstance = QContext.getQInstance(); + qInstance.addReport(definePivotReport()); + insertPersonRecords(qInstance); + + ReportInput reportInput = new ReportInput(); + reportInput.setReportName(REPORT_NAME); + reportInput.setReportDestination(new ReportDestination().withReportFormat(ReportFormat.XLSX).withReportOutputStream(fileOutputStream)); + reportInput.setInputValues(Map.of("startDate", LocalDate.of(1970, Month.MAY, 15), "endDate", LocalDate.now())); + new GenerateReportAction().execute(reportInput); + System.out.println("Wrote File: " + name); + + // LocalMacDevUtils.mayOpenFiles = true; + LocalMacDevUtils.openFile(name); + } + + /////////////////////////////////////////////////////////// + // read the file we wrote, and assert about its contents // + /////////////////////////////////////////////////////////// + FileInputStream file = new FileInputStream(name); + XSSFWorkbook workbook = new XSSFWorkbook(file); + + XSSFSheet sheet = workbook.getSheetAt(1); + List pivotTables = sheet.getPivotTables(); + XSSFPivotTable xssfPivotTable = pivotTables.get(0); + List rowLabelColumns = xssfPivotTable.getRowLabelColumns(); + List colLabelColumns = xssfPivotTable.getColLabelColumns(); + Sheet dataSheet = xssfPivotTable.getDataSheet(); + Sheet parentSheet = xssfPivotTable.getParentSheet(); + System.out.println(); + + Map> data = new HashMap<>(); + int i = 0; + for(Row row : sheet) + { + data.put(i, new ArrayList<>()); + + for(Cell cell : row) + { + data.get(i).add(switch(cell.getCellType()) + { + case _NONE -> "<_NONE>"; + case NUMERIC -> cell.getNumericCellValue(); + case STRING -> cell.getStringCellValue(); + case FORMULA -> cell.getCellFormula(); + case BLANK -> ""; + case BOOLEAN -> cell.getBooleanCellValue(); + case ERROR -> cell.getErrorCellValue(); + }); + } + i++; + } + + System.out.println(data); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -369,8 +478,7 @@ public class GenerateReportActionTest extends BaseTest { ReportInput reportInput = new ReportInput(); reportInput.setReportName(REPORT_NAME); - reportInput.setReportFormat(ReportFormat.LIST_OF_MAPS); - reportInput.setReportOutputStream(new ByteArrayOutputStream()); + reportInput.setReportDestination(new ReportDestination().withReportFormat(ReportFormat.LIST_OF_MAPS).withReportOutputStream(new ByteArrayOutputStream())); reportInput.setInputValues(inputValues); new GenerateReportAction().execute(reportInput); } @@ -383,12 +491,12 @@ public class GenerateReportActionTest extends BaseTest private void insertPersonRecords(QInstance qInstance) throws QException { TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of( - new PersonQRecord().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().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().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().withLastName("Keller").withBirthDate(LocalDate.of(1980, Month.JANUARY, 7)).withNoOfShoes(5).withHomeStateId(1).withPrice(new BigDecimal("2.40")).withCost(new BigDecimal("3.50")), - new PersonQRecord().withLastName("Kelkhoff").withBirthDate(LocalDate.of(1980, Month.FEBRUARY, 15)).withNoOfShoes(6).withHomeStateId(1).withPrice(new BigDecimal("3.60")).withCost(new BigDecimal("3.50")), - new PersonQRecord().withLastName("Kelkhoff").withBirthDate(LocalDate.of(1980, Month.MARCH, 20)).withNoOfShoes(7).withHomeStateId(2).withPrice(new BigDecimal("4.80")).withCost(new BigDecimal("3.50")) + 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("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("Trevor").withLastName("Keller").withBirthDate(LocalDate.of(1980, Month.JANUARY, 7)).withNoOfShoes(5).withHomeStateId(1).withPrice(new BigDecimal("2.40")).withCost(new BigDecimal("3.50")), + new PersonQRecord().withFirstName("Trevor").withLastName("Kelkhoff").withBirthDate(LocalDate.of(1980, Month.FEBRUARY, 15)).withNoOfShoes(6).withHomeStateId(1).withPrice(new BigDecimal("3.60")).withCost(new BigDecimal("3.50")), + new PersonQRecord().withFirstName("Kelly").withLastName("Kelkhoff").withBirthDate(LocalDate.of(1980, Month.MARCH, 20)).withNoOfShoes(7).withHomeStateId(2).withPrice(new BigDecimal("4.80")).withCost(new BigDecimal("3.50")) )); } @@ -397,7 +505,7 @@ public class GenerateReportActionTest extends BaseTest /******************************************************************************* ** *******************************************************************************/ - public static QReportMetaData definePersonShoesPivotReport(boolean includeTotalRow) + public static QReportMetaData definePersonShoesSummaryReport(boolean includeTotalRow) { return new QReportMetaData() .withName(REPORT_NAME) @@ -420,7 +528,7 @@ public class GenerateReportActionTest extends BaseTest .withLabel("pivot") .withDataSourceName("persons") .withType(ReportType.SUMMARY) - .withPivotFields(List.of("lastName")) + .withSummaryFields(List.of("lastName")) .withIncludeTotalRow(includeTotalRow) .withTitleFormat("Number of shoes - people born between %s and %s - pivot on LastName, sort by Quantity, Revenue DESC") .withTitleFields(List.of("${input.startDate}", "${input.endDate}")) @@ -452,33 +560,8 @@ public class GenerateReportActionTest extends BaseTest @Test void testTableOnlyReport() throws QException { - QInstance qInstance = QContext.getQInstance(); - QReportMetaData report = new QReportMetaData() - .withName(REPORT_NAME) - .withDataSources(List.of( - new QReportDataSource() - .withName("persons") - .withSourceTable(TestUtils.TABLE_NAME_PERSON_MEMORY) - .withQueryFilter(new QQueryFilter() - .withCriteria(new QFilterCriteria("birthDate", QCriteriaOperator.GREATER_THAN, List.of("${input.startDate}"))) - ) - )) - .withInputFields(List.of( - new QFieldMetaData("startDate", QFieldType.DATE_TIME) - )) - .withViews(List.of( - new QReportView() - .withName("table1") - .withLabel("table1") - .withDataSourceName("persons") - .withType(ReportType.TABLE) - .withColumns(List.of( - new QReportField().withName("id"), - new QReportField().withName("firstName"), - new QReportField().withName("lastName") - )) - )); - + QInstance qInstance = QContext.getQInstance(); + QReportMetaData report = defineTableOnlyReport(); qInstance.addReport(report); insertPersonRecords(qInstance); @@ -493,6 +576,86 @@ public class GenerateReportActionTest extends BaseTest + /******************************************************************************* + ** + *******************************************************************************/ + private static QReportMetaData defineTableOnlyReport() + { + QReportMetaData report = new QReportMetaData() + .withName(REPORT_NAME) + .withDataSources(List.of( + new QReportDataSource() + .withName("persons") + .withSourceTable(TestUtils.TABLE_NAME_PERSON_MEMORY) + .withQueryFilter(new QQueryFilter() + .withCriteria(new QFilterCriteria("birthDate", QCriteriaOperator.GREATER_THAN, List.of("${input.startDate}")))))) + + .withInputFields(List.of( + new QFieldMetaData("startDate", QFieldType.DATE_TIME))) + + .withViews(List.of( + new QReportView() + .withName("table1") + .withLabel("table1") + .withDataSourceName("persons") + .withType(ReportType.TABLE) + .withColumns(List.of( + new QReportField().withName("id"), + new QReportField().withName("firstName"), + new QReportField().withName("lastName"))))); + + return report; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + private static QReportMetaData definePivotReport() + { + QReportMetaData report = new QReportMetaData() + .withName(REPORT_NAME) + .withDataSources(List.of( + new QReportDataSource() + .withName("persons") + .withSourceTable(TestUtils.TABLE_NAME_PERSON_MEMORY) + .withQueryFilter(new QQueryFilter() + .withCriteria(new QFilterCriteria("birthDate", QCriteriaOperator.GREATER_THAN, List.of("${input.startDate}")))))) + + .withInputFields(List.of( + new QFieldMetaData("startDate", QFieldType.DATE_TIME))) + + .withViews(List.of( + + new QReportView() + .withName("table1") + .withLabel("table1") + .withDataSourceName("persons") + .withType(ReportType.TABLE) + .withColumns(List.of( + new QReportField().withName("id"), + new QReportField().withName("firstName"), + new QReportField().withName("lastName"))), + + new QReportView() + .withName("pivotTable1") + .withLabel("My Pivot Table") + + .withType(ReportType.PIVOT) + .withPivotTableSourceViewName("table1") + .withPivotTableDefinition(new PivotTableDefinition() + .withRow(new PivotTableGroupBy().withFieldName("firstName")) + .withRow(new PivotTableGroupBy().withFieldName("lastName")) + // .withColumn(new PivotTableGroupBy().withFieldName("firstName")) + .withValue(new PivotTableValue().withFunction(PivotTableFunction.COUNT).withFieldName("id"))) + )); + + return report; + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -566,8 +729,7 @@ public class GenerateReportActionTest extends BaseTest ReportInput reportInput = new ReportInput(); reportInput.setReportName(TestUtils.REPORT_NAME_PERSON_SIMPLE); - reportInput.setReportFormat(ReportFormat.LIST_OF_MAPS); - reportInput.setReportOutputStream(new ByteArrayOutputStream()); + reportInput.setReportDestination(new ReportDestination().withReportFormat(ReportFormat.LIST_OF_MAPS).withReportOutputStream(new ByteArrayOutputStream())); new GenerateReportAction().execute(reportInput); List> list = ListOfMapsExportStreamer.getList("Simple Report"); diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/ConvertHtmlToPdfActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/ConvertHtmlToPdfActionTest.java index 83dd98ef..4249275c 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/ConvertHtmlToPdfActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/ConvertHtmlToPdfActionTest.java @@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.model.actions.templates.RenderTemplateInpu import com.kingsrook.qqq.backend.core.model.actions.templates.RenderTemplateOutput; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.templates.TemplateType; +import com.kingsrook.qqq.backend.core.utils.LocalMacDevUtils; import org.junit.jupiter.api.Test; @@ -107,8 +108,8 @@ class ConvertHtmlToPdfActionTest extends BaseTest ///////////////////////////////////////////////////////////////////////// // for local dev on a mac, turn this on to auto-open the generated PDF // ///////////////////////////////////////////////////////////////////////// - // todo not commit - // Runtime.getRuntime().exec(new String[] { "/usr/bin/open", "/tmp/file.pdf" }); + // LocalMacDevUtils.mayOpenFiles = true; + LocalMacDevUtils.openFile("/tmp/file.pdf"); } } \ No newline at end of file diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/DynamicDefaultValueBehaviorTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/DynamicDefaultValueBehaviorTest.java index ad07b882..39d0af14 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/DynamicDefaultValueBehaviorTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/fields/DynamicDefaultValueBehaviorTest.java @@ -34,6 +34,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.utils.TestUtils; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -156,4 +157,47 @@ class DynamicDefaultValueBehaviorTest extends BaseTest assertNull(record.getValue("firstName")); } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testUserId() + { + QInstance qInstance = QContext.getQInstance(); + QTableMetaData table = qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY); + table.getField("firstName").withBehavior(DynamicDefaultValueBehavior.USER_ID); + + { + //////////////////////////////// + // set it (if null) on insert // + //////////////////////////////// + QRecord record = new QRecord().withValue("id", 1); + ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.INSERT, qInstance, table, List.of(record), null); + assertEquals(QContext.getQSession().getUser().getIdReference(), record.getValue("firstName")); + } + + { + //////////////////////////////// + // set it (if null) on update // + //////////////////////////////// + QRecord record = new QRecord().withValue("id", 1); + ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.UPDATE, qInstance, table, List.of(record), null); + assertEquals(QContext.getQSession().getUser().getIdReference(), record.getValue("firstName")); + } + + { + //////////////////////////////////////////////////////////////////// + // only set it if it wasn't previously set (both insert & update) // + //////////////////////////////////////////////////////////////////// + QRecord record = new QRecord().withValue("id", 1).withValue("firstName", "Bob"); + ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.INSERT, qInstance, table, List.of(record), null); + assertEquals("Bob", record.getValue("firstName")); + + ValueBehaviorApplier.applyFieldBehaviors(ValueBehaviorApplier.Action.UPDATE, qInstance, table, List.of(record), null); + assertEquals("Bob", record.getValue("firstName")); + } + } + } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/reports/BasicRunReportProcessTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/reports/BasicRunReportProcessTest.java index de193fc6..d84e0a97 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/reports/BasicRunReportProcessTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/processes/implementations/reports/BasicRunReportProcessTest.java @@ -50,7 +50,7 @@ class BasicRunReportProcessTest extends BaseTest void testRunReport() throws QException { QInstance instance = TestUtils.defineInstance(); - QReportMetaData report = GenerateReportActionTest.definePersonShoesPivotReport(true); + QReportMetaData report = GenerateReportActionTest.definePersonShoesSummaryReport(true); QProcessMetaData runReportProcess = BasicRunReportProcess.defineProcessMetaData(); instance.addReport(report); diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/testutils/PersonQRecord.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/testutils/PersonQRecord.java index 7f7bdf6f..d5620731 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/testutils/PersonQRecord.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/testutils/PersonQRecord.java @@ -40,6 +40,14 @@ public class PersonQRecord extends QRecord + public PersonQRecord withFirstName(String firstName) + { + setValue("firstName", firstName); + return (this); + } + + + public PersonQRecord withBirthDate(LocalDate birthDate) { setValue("birthDate", birthDate);