mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Add static data provider capability to reports
This commit is contained in:
@ -73,7 +73,7 @@ public class CsvExportStreamer implements ExportStreamerInterface
|
|||||||
table = exportInput.getTable();
|
table = exportInput.getTable();
|
||||||
outputStream = this.exportInput.getReportOutputStream();
|
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
|
try
|
||||||
{
|
{
|
||||||
@ -90,16 +90,20 @@ public class CsvExportStreamer implements ExportStreamerInterface
|
|||||||
outputStream.write((exportInput.getTitleRow() + "\n").getBytes(StandardCharsets.UTF_8));
|
outputStream.write((exportInput.getTitleRow() + "\n").getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
int col = 0;
|
if(exportInput.getIncludeHeaderRow())
|
||||||
for(QFieldMetaData column : fields)
|
|
||||||
{
|
{
|
||||||
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();
|
outputStream.flush();
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
|
@ -130,7 +130,7 @@ public class ExcelExportStreamer implements ExportStreamerInterface
|
|||||||
|
|
||||||
worksheet = workbook.newWorksheet(Objects.requireNonNullElse(label, "Sheet " + sheetCount));
|
worksheet = workbook.newWorksheet(Objects.requireNonNullElse(label, "Sheet " + sheetCount));
|
||||||
|
|
||||||
writeReportHeaderRow();
|
writeTitleAndHeader();
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
@ -143,7 +143,7 @@ public class ExcelExportStreamer implements ExportStreamerInterface
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private void writeReportHeaderRow() throws QReportingException
|
private void writeTitleAndHeader() throws QReportingException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -160,25 +160,28 @@ public class ExcelExportStreamer implements ExportStreamerInterface
|
|||||||
titleStyle.set();
|
titleStyle.set();
|
||||||
|
|
||||||
row++;
|
row++;
|
||||||
|
worksheet.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// header row //
|
// header row //
|
||||||
////////////////
|
////////////////
|
||||||
int col = 0;
|
if(exportInput.getIncludeHeaderRow())
|
||||||
for(QFieldMetaData column : fields)
|
|
||||||
{
|
{
|
||||||
worksheet.value(row, col, column.getLabel());
|
int col = 0;
|
||||||
col++;
|
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)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
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;
|
||||||
@ -180,10 +181,15 @@ public class GenerateReportAction
|
|||||||
{
|
{
|
||||||
QTableMetaData table = reportInput.getInstance().getTable(dataSource.getSourceTable());
|
QTableMetaData table = reportInput.getInstance().getTable(dataSource.getSourceTable());
|
||||||
|
|
||||||
|
QMetaDataVariableInterpreter variableInterpreter = new QMetaDataVariableInterpreter();
|
||||||
|
variableInterpreter.addValueMap("input", reportInput.getInputValues());
|
||||||
|
|
||||||
ExportInput exportInput = new ExportInput(reportInput.getInstance());
|
ExportInput exportInput = new ExportInput(reportInput.getInstance());
|
||||||
exportInput.setSession(reportInput.getSession());
|
exportInput.setSession(reportInput.getSession());
|
||||||
exportInput.setReportFormat(reportFormat);
|
exportInput.setReportFormat(reportFormat);
|
||||||
exportInput.setFilename(reportInput.getFilename());
|
exportInput.setFilename(reportInput.getFilename());
|
||||||
|
exportInput.setTitleRow(getTitle(reportView, variableInterpreter));
|
||||||
|
exportInput.setIncludeHeaderRow(reportView.getHeaderRow());
|
||||||
exportInput.setReportOutputStream(reportInput.getReportOutputStream());
|
exportInput.setReportOutputStream(reportInput.getReportOutputStream());
|
||||||
|
|
||||||
List<QFieldMetaData> fields;
|
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
|
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 //
|
// 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();
|
RecordPipe recordPipe = new RecordPipe();
|
||||||
new AsyncRecordPipeLoop().run("Report[" + reportInput.getReportName() + "]", null, recordPipe, (callback) ->
|
new AsyncRecordPipeLoop().run("Report[" + reportInput.getReportName() + "]", null, recordPipe, (callback) ->
|
||||||
{
|
{
|
||||||
QueryInput queryInput = new QueryInput(reportInput.getInstance());
|
if(dataSource.getSourceTable() != null)
|
||||||
queryInput.setSession(reportInput.getSession());
|
{
|
||||||
queryInput.setRecordPipe(recordPipe);
|
QQueryFilter queryFilter = dataSource.getQueryFilter().clone();
|
||||||
queryInput.setTableName(dataSource.getSourceTable());
|
setInputValuesInQueryFilter(reportInput, queryFilter);
|
||||||
queryInput.setFilter(queryFilter);
|
|
||||||
queryInput.setShouldTranslatePossibleValues(true); // todo - any limits or conditions on this?
|
QueryInput queryInput = new QueryInput(reportInput.getInstance());
|
||||||
return (new QueryAction().execute(queryInput));
|
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();
|
List<QRecord> records = recordPipe.consumeAvailableRecords();
|
||||||
@ -465,6 +495,7 @@ public class GenerateReportAction
|
|||||||
exportInput.setReportFormat(reportFormat);
|
exportInput.setReportFormat(reportFormat);
|
||||||
exportInput.setFilename(reportInput.getFilename());
|
exportInput.setFilename(reportInput.getFilename());
|
||||||
exportInput.setTitleRow(pivotOutput.titleRow);
|
exportInput.setTitleRow(pivotOutput.titleRow);
|
||||||
|
exportInput.setIncludeHeaderRow(view.getHeaderRow());
|
||||||
exportInput.setReportOutputStream(reportInput.getReportOutputStream());
|
exportInput.setReportOutputStream(reportInput.getReportOutputStream());
|
||||||
|
|
||||||
reportStreamer.setDisplayFormats(getDisplayFormatMap(view));
|
reportStreamer.setDisplayFormats(getDisplayFormatMap(view));
|
||||||
@ -540,26 +571,7 @@ public class GenerateReportAction
|
|||||||
///////////
|
///////////
|
||||||
// title //
|
// title //
|
||||||
///////////
|
///////////
|
||||||
String title = null;
|
String title = getTitle(view, variableInterpreter);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
// headers //
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -96,10 +96,14 @@ public class ListOfMapsExportStreamer implements ExportStreamerInterface
|
|||||||
currentSheetLabel = label;
|
currentSheetLabel = label;
|
||||||
|
|
||||||
rows.put(label, new ArrayList<>());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ public class ExportInput extends AbstractTableActionInput
|
|||||||
private ReportFormat reportFormat;
|
private ReportFormat reportFormat;
|
||||||
private OutputStream reportOutputStream;
|
private OutputStream reportOutputStream;
|
||||||
private String titleRow;
|
private String titleRow;
|
||||||
|
private boolean includeHeaderRow = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -225,4 +226,27 @@ public class ExportInput extends AbstractTableActionInput
|
|||||||
{
|
{
|
||||||
this.titleRow = titleRow;
|
this.titleRow = titleRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for includeHeaderRow
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public boolean getIncludeHeaderRow()
|
||||||
|
{
|
||||||
|
return includeHeaderRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for includeHeaderRow
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIncludeHeaderRow(boolean includeHeaderRow)
|
||||||
|
{
|
||||||
|
this.includeHeaderRow = includeHeaderRow;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,5 +31,6 @@ public enum QCodeUsage
|
|||||||
BACKEND_STEP, // a backend-step in a process
|
BACKEND_STEP, // a backend-step in a process
|
||||||
CUSTOMIZER, // a function to customize part of a QQQ table's behavior
|
CUSTOMIZER, // a function to customize part of a QQQ table's behavior
|
||||||
POSSIBLE_VALUE_PROVIDER, // code that drives a custom possibleValueSource
|
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
|
||||||
}
|
}
|
||||||
|
@ -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.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 String sourceTable;
|
||||||
private QQueryFilter queryFilter;
|
private QQueryFilter queryFilter;
|
||||||
|
|
||||||
|
private QCodeReference staticDataSupplier;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -136,4 +139,38 @@ public class QReportDataSource
|
|||||||
return (this);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ public class QReportView implements Cloneable
|
|||||||
private String titleFormat;
|
private String titleFormat;
|
||||||
private List<String> titleFields;
|
private List<String> titleFields;
|
||||||
private List<String> pivotFields;
|
private List<String> pivotFields;
|
||||||
|
private boolean headerRow = true;
|
||||||
private boolean totalRow = false;
|
private boolean totalRow = false;
|
||||||
private boolean pivotSubTotals = false;
|
private boolean pivotSubTotals = false;
|
||||||
private List<QReportField> columns;
|
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
|
** Getter for totalRow
|
||||||
**
|
**
|
||||||
|
Reference in New Issue
Block a user