Add static data provider capability to reports

This commit is contained in:
2022-09-29 16:55:08 -05:00
parent 2d2eae5c06
commit 456364de2a
8 changed files with 206 additions and 56 deletions

View File

@ -73,7 +73,7 @@ public class CsvExportStreamer implements ExportStreamerInterface
table = exportInput.getTable();
outputStream = this.exportInput.getReportOutputStream();
writeReportHeaderRow();
writeTitleAndHeader();
}
@ -81,7 +81,7 @@ public class CsvExportStreamer implements ExportStreamerInterface
/*******************************************************************************
**
*******************************************************************************/
private void writeReportHeaderRow() throws QReportingException
private void writeTitleAndHeader() throws QReportingException
{
try
{
@ -90,16 +90,20 @@ public class CsvExportStreamer implements ExportStreamerInterface
outputStream.write((exportInput.getTitleRow() + "\n").getBytes(StandardCharsets.UTF_8));
}
int col = 0;
for(QFieldMetaData column : fields)
if(exportInput.getIncludeHeaderRow())
{
if(col++ > 0)
int col = 0;
for(QFieldMetaData column : fields)
{
outputStream.write(',');
if(col++ > 0)
{
outputStream.write(',');
}
outputStream.write(('"' + column.getLabel() + '"').getBytes(StandardCharsets.UTF_8));
}
outputStream.write(('"' + column.getLabel() + '"').getBytes(StandardCharsets.UTF_8));
outputStream.write('\n');
}
outputStream.write('\n');
outputStream.flush();
}
catch(Exception e)

View File

@ -130,7 +130,7 @@ public class ExcelExportStreamer implements ExportStreamerInterface
worksheet = workbook.newWorksheet(Objects.requireNonNullElse(label, "Sheet " + sheetCount));
writeReportHeaderRow();
writeTitleAndHeader();
}
catch(Exception e)
{
@ -143,7 +143,7 @@ public class ExcelExportStreamer implements ExportStreamerInterface
/*******************************************************************************
**
*******************************************************************************/
private void writeReportHeaderRow() throws QReportingException
private void writeTitleAndHeader() throws QReportingException
{
try
{
@ -160,25 +160,28 @@ public class ExcelExportStreamer implements ExportStreamerInterface
titleStyle.set();
row++;
worksheet.flush();
}
////////////////
// header row //
////////////////
int col = 0;
for(QFieldMetaData column : fields)
if(exportInput.getIncludeHeaderRow())
{
worksheet.value(row, col, column.getLabel());
col++;
int col = 0;
for(QFieldMetaData column : fields)
{
worksheet.value(row, col, column.getLabel());
col++;
}
StyleSetter headerStyle = worksheet.range(row, 0, row, fields.size() - 1).style();
excelStylerInterface.styleHeaderRow(headerStyle);
headerStyle.set();
row++;
worksheet.flush();
}
StyleSetter headerStyle = worksheet.range(row, 0, row, fields.size() - 1).style();
excelStylerInterface.styleHeaderRow(headerStyle);
headerStyle.set();
row++;
worksheet.flush();
}
catch(Exception e)
{

View File

@ -30,6 +30,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.kingsrook.qqq.backend.core.actions.async.AsyncRecordPipeLoop;
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
@ -180,10 +181,15 @@ public class GenerateReportAction
{
QTableMetaData table = reportInput.getInstance().getTable(dataSource.getSourceTable());
QMetaDataVariableInterpreter variableInterpreter = new QMetaDataVariableInterpreter();
variableInterpreter.addValueMap("input", reportInput.getInputValues());
ExportInput exportInput = new ExportInput(reportInput.getInstance());
exportInput.setSession(reportInput.getSession());
exportInput.setReportFormat(reportFormat);
exportInput.setFilename(reportInput.getFilename());
exportInput.setTitleRow(getTitle(reportView, variableInterpreter));
exportInput.setIncludeHeaderRow(reportView.getHeaderRow());
exportInput.setReportOutputStream(reportInput.getReportOutputStream());
List<QFieldMetaData> fields;
@ -222,9 +228,6 @@ public class GenerateReportAction
*******************************************************************************/
private void gatherData(ReportInput reportInput, QReportDataSource dataSource, QReportView tableView, List<QReportView> pivotViews, List<QReportView> variantViews) throws QException
{
QQueryFilter queryFilter = dataSource.getQueryFilter().clone();
setInputValuesInQueryFilter(reportInput, queryFilter);
////////////////////////////////////////////////////////////////////////////////////////
// check if this view has a transform step - if so, set it up now and run its pre-run //
////////////////////////////////////////////////////////////////////////////////////////
@ -257,13 +260,40 @@ public class GenerateReportAction
RecordPipe recordPipe = new RecordPipe();
new AsyncRecordPipeLoop().run("Report[" + reportInput.getReportName() + "]", null, recordPipe, (callback) ->
{
QueryInput queryInput = new QueryInput(reportInput.getInstance());
queryInput.setSession(reportInput.getSession());
queryInput.setRecordPipe(recordPipe);
queryInput.setTableName(dataSource.getSourceTable());
queryInput.setFilter(queryFilter);
queryInput.setShouldTranslatePossibleValues(true); // todo - any limits or conditions on this?
return (new QueryAction().execute(queryInput));
if(dataSource.getSourceTable() != null)
{
QQueryFilter queryFilter = dataSource.getQueryFilter().clone();
setInputValuesInQueryFilter(reportInput, queryFilter);
QueryInput queryInput = new QueryInput(reportInput.getInstance());
queryInput.setSession(reportInput.getSession());
queryInput.setRecordPipe(recordPipe);
queryInput.setTableName(dataSource.getSourceTable());
queryInput.setFilter(queryFilter);
queryInput.setShouldTranslatePossibleValues(true); // todo - any limits or conditions on this?
return (new QueryAction().execute(queryInput));
}
else if(dataSource.getStaticDataSupplier() != null)
{
@SuppressWarnings("unchecked")
Supplier<List<List<Serializable>>> supplier = QCodeLoader.getAdHoc(Supplier.class, dataSource.getStaticDataSupplier());
List<List<Serializable>> lists = supplier.get();
for(List<Serializable> list : lists)
{
QRecord record = new QRecord();
int index = 0;
for(Serializable value : list)
{
record.setValue("column" + (index++), value);
}
recordPipe.addRecord(record);
}
return (true);
}
else
{
throw (new IllegalStateException("Misconfigured data source [" + dataSource.getName() + "]."));
}
}, () ->
{
List<QRecord> records = recordPipe.consumeAvailableRecords();
@ -465,6 +495,7 @@ public class GenerateReportAction
exportInput.setReportFormat(reportFormat);
exportInput.setFilename(reportInput.getFilename());
exportInput.setTitleRow(pivotOutput.titleRow);
exportInput.setIncludeHeaderRow(view.getHeaderRow());
exportInput.setReportOutputStream(reportInput.getReportOutputStream());
reportStreamer.setDisplayFormats(getDisplayFormatMap(view));
@ -540,26 +571,7 @@ public class GenerateReportAction
///////////
// title //
///////////
String title = null;
if(view.getTitleFields() != null && StringUtils.hasContent(view.getTitleFormat()))
{
List<String> titleValues = new ArrayList<>();
for(String titleField : view.getTitleFields())
{
titleValues.add(variableInterpreter.interpret(titleField));
}
title = valueFormatter.formatStringWithValues(view.getTitleFormat(), titleValues);
}
else if(StringUtils.hasContent(view.getTitleFormat()))
{
title = view.getTitleFormat();
}
if(StringUtils.hasContent(title))
{
System.out.println(title);
}
String title = getTitle(view, variableInterpreter);
/////////////
// headers //
@ -701,6 +713,36 @@ public class GenerateReportAction
/*******************************************************************************
**
*******************************************************************************/
private String getTitle(QReportView view, QMetaDataVariableInterpreter variableInterpreter)
{
String title = null;
if(view.getTitleFields() != null && StringUtils.hasContent(view.getTitleFormat()))
{
List<String> titleValues = new ArrayList<>();
for(String titleField : view.getTitleFields())
{
titleValues.add(variableInterpreter.interpret(titleField));
}
title = new QValueFormatter().formatStringWithValues(view.getTitleFormat(), titleValues);
}
else if(StringUtils.hasContent(view.getTitleFormat()))
{
title = view.getTitleFormat();
}
if(StringUtils.hasContent(title))
{
System.out.println(title);
}
return title;
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -96,10 +96,14 @@ public class ListOfMapsExportStreamer implements ExportStreamerInterface
currentSheetLabel = label;
rows.put(label, new ArrayList<>());
headers.put(label, new ArrayList<>());
for(QFieldMetaData field : fields)
if(exportInput.getIncludeHeaderRow())
{
headers.get(label).add(field.getLabel());
headers.put(label, new ArrayList<>());
for(QFieldMetaData field : fields)
{
headers.get(label).add(field.getLabel());
}
}
}

View File

@ -43,6 +43,7 @@ public class ExportInput extends AbstractTableActionInput
private ReportFormat reportFormat;
private OutputStream reportOutputStream;
private String titleRow;
private boolean includeHeaderRow = true;
@ -225,4 +226,27 @@ public class ExportInput extends AbstractTableActionInput
{
this.titleRow = titleRow;
}
/*******************************************************************************
** Getter for includeHeaderRow
**
*******************************************************************************/
public boolean getIncludeHeaderRow()
{
return includeHeaderRow;
}
/*******************************************************************************
** Setter for includeHeaderRow
**
*******************************************************************************/
public void setIncludeHeaderRow(boolean includeHeaderRow)
{
this.includeHeaderRow = includeHeaderRow;
}
}

View File

@ -31,5 +31,6 @@ public enum QCodeUsage
BACKEND_STEP, // a backend-step in a process
CUSTOMIZER, // a function to customize part of a QQQ table's behavior
POSSIBLE_VALUE_PROVIDER, // code that drives a custom possibleValueSource
RECORD_AUTOMATION_HANDLER // code that executes record automations
RECORD_AUTOMATION_HANDLER, // code that executes record automations
REPORT_STATIC_DATA_SUPPLIER // code that supplies static data to a report
}

View File

@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.reporting;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
/*******************************************************************************
@ -34,6 +35,8 @@ public class QReportDataSource
private String sourceTable;
private QQueryFilter queryFilter;
private QCodeReference staticDataSupplier;
/*******************************************************************************
@ -136,4 +139,38 @@ public class QReportDataSource
return (this);
}
/*******************************************************************************
** Getter for staticDataSupplier
**
*******************************************************************************/
public QCodeReference getStaticDataSupplier()
{
return staticDataSupplier;
}
/*******************************************************************************
** Setter for staticDataSupplier
**
*******************************************************************************/
public void setStaticDataSupplier(QCodeReference staticDataSupplier)
{
this.staticDataSupplier = staticDataSupplier;
}
/*******************************************************************************
** Fluent setter for staticDataSupplier
**
*******************************************************************************/
public QReportDataSource withStaticDataSupplier(QCodeReference staticDataSupplier)
{
this.staticDataSupplier = staticDataSupplier;
return (this);
}
}

View File

@ -41,6 +41,7 @@ public class QReportView implements Cloneable
private String titleFormat;
private List<String> titleFields;
private List<String> pivotFields;
private boolean headerRow = true;
private boolean totalRow = false;
private boolean pivotSubTotals = false;
private List<QReportField> columns;
@ -327,6 +328,40 @@ public class QReportView implements Cloneable
/*******************************************************************************
** Getter for headerRow
**
*******************************************************************************/
public boolean getHeaderRow()
{
return headerRow;
}
/*******************************************************************************
** Setter for headerRow
**
*******************************************************************************/
public void setHeaderRow(boolean headerRow)
{
this.headerRow = headerRow;
}
/*******************************************************************************
** Fluent setter for headerRow
**
*******************************************************************************/
public QReportView withHeaderRow(boolean headerRow)
{
this.headerRow = headerRow;
return (this);
}
/*******************************************************************************
** Getter for totalRow
**