CE-881 - Update RenderSavedReport process to stream results to a backend through new StorageAction.

This commit is contained in:
2024-04-01 12:53:02 -05:00
parent 6fffe3036c
commit 3914670988
6 changed files with 197 additions and 75 deletions

View File

@ -24,13 +24,21 @@ package com.kingsrook.qqq.backend.core.model.savedreports;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.DefaultWidgetRenderer;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormatPossibleValueEnum; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormatPossibleValueEnum;
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface;
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType; import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment; import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
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.layout.QIcon; import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection; import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier; import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier;
@ -42,17 +50,66 @@ import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.Ren
*******************************************************************************/ *******************************************************************************/
public class SavedReportsMetaDataProvider public class SavedReportsMetaDataProvider
{ {
public static final String REPORT_STORAGE_TABLE_NAME = "reportStorage";
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public void defineAll(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException public void defineAll(QInstance instance, String recordTablesBackendName, String reportStorageBackendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
{ {
instance.addTable(defineSavedReportTable(backendName, backendDetailEnricher)); instance.addTable(defineSavedReportTable(recordTablesBackendName, backendDetailEnricher));
instance.addPossibleValueSource(QPossibleValueSource.newForTable(SavedReport.TABLE_NAME)); instance.addPossibleValueSource(QPossibleValueSource.newForTable(SavedReport.TABLE_NAME));
instance.addPossibleValueSource(QPossibleValueSource.newForEnum(ReportFormatPossibleValueEnum.NAME, ReportFormatPossibleValueEnum.values())); instance.addPossibleValueSource(QPossibleValueSource.newForEnum(ReportFormatPossibleValueEnum.NAME, ReportFormatPossibleValueEnum.values()));
instance.addProcess(new RenderSavedReportMetaDataProducer().produce(instance));
instance.addTable(defineReportStorageTable(reportStorageBackendName, backendDetailEnricher));
QProcessMetaData renderSavedReportProcess = new RenderSavedReportMetaDataProducer().produce(instance);
instance.addProcess(renderSavedReportProcess);
renderSavedReportProcess.getInputFields().stream()
.filter(f -> RenderSavedReportMetaDataProducer.FIELD_NAME_STORAGE_TABLE_NAME.equals(f.getName()))
.findFirst()
.ifPresent(f -> f.setDefaultValue(REPORT_STORAGE_TABLE_NAME));
instance.addWidget(defineReportSetupWidget());
}
/*******************************************************************************
**
*******************************************************************************/
private QTableMetaData defineReportStorageTable(String backendName, Consumer<QTableMetaData> backendDetailEnricher)
{
QTableMetaData table = new QTableMetaData()
.withName(REPORT_STORAGE_TABLE_NAME)
.withBackendName(backendName)
.withPrimaryKeyField("reference")
.withField(new QFieldMetaData("reference", QFieldType.STRING))
.withField(new QFieldMetaData("contents", QFieldType.BLOB));
if(backendDetailEnricher != null)
{
backendDetailEnricher.accept(table);
}
return (table);
}
/*******************************************************************************
**
*******************************************************************************/
private QWidgetMetaDataInterface defineReportSetupWidget()
{
return new QWidgetMetaData()
.withName("reportSetupWidget")
.withLabel("Report Setup")
.withIsCard(true)
.withType(WidgetType.REPORT_SETUP.getType())
.withCodeReference(new QCodeReference(DefaultWidgetRenderer.class));
} }
@ -73,6 +130,7 @@ public class SavedReportsMetaDataProvider
.withFieldsFromEntity(SavedReport.class) .withFieldsFromEntity(SavedReport.class)
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "label"))) .withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "label")))
.withSection(new QFieldSection("settings", new QIcon().withName("settings"), Tier.T2, List.of("tableName"))) .withSection(new QFieldSection("settings", new QIcon().withName("settings"), Tier.T2, List.of("tableName")))
.withSection(new QFieldSection("reportSetup", new QIcon().withName("table_chart"), Tier.T2).withWidgetName("reportSetupWidget"))
.withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("queryFilterJson", "columnsJson", "pivotTableJson"))) .withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("queryFilterJson", "columnsJson", "pivotTableJson")))
.withSection(new QFieldSection("hidden", new QIcon().withName("text_snippet"), Tier.T2, List.of("inputFieldsJson", "userId")).withIsHidden(true)) .withSection(new QFieldSection("hidden", new QIcon().withName("text_snippet"), Tier.T2, List.of("inputFieldsJson", "userId")).withIsHidden(true))
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate"))); .withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));

View File

@ -22,15 +22,16 @@
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports; package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
import java.io.File; import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction; import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction;
import com.kingsrook.qqq.backend.core.actions.tables.StorageAction;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
@ -38,6 +39,7 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutp
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination; 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.ReportFormat;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.storage.StorageInput;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData; import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport; import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils;
@ -60,32 +62,33 @@ public class RenderSavedReportExecuteStep implements BackendStep
{ {
try try
{ {
ReportFormat reportFormat = ReportFormat.fromString(runBackendStepInput.getValueString("reportFormat")); String storageTableName = runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_STORAGE_TABLE_NAME);
ReportFormat reportFormat = ReportFormat.fromString(runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_REPORT_FORMAT));
SavedReport savedReport = new SavedReport(runBackendStepInput.getRecords().get(0)); SavedReport savedReport = new SavedReport(runBackendStepInput.getRecords().get(0));
File tmpFile = File.createTempFile("SavedReport" + savedReport.getId(), "." + reportFormat.getExtension(), new File("/tmp/")); String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, savedReport);
String storageReference = UUID.randomUUID() + "/" + downloadFileBaseName + "." + reportFormat.getExtension();
OutputStream outputStream = new StorageAction().createOutputStream(new StorageInput(storageTableName).withReference(storageReference));
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report"); runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
QReportMetaData reportMetaData = new SavedReportToReportMetaDataAdapter().adapt(savedReport, reportFormat); QReportMetaData reportMetaData = new SavedReportToReportMetaDataAdapter().adapt(savedReport, reportFormat);
try(FileOutputStream reportOutputStream = new FileOutputStream(tmpFile))
{
ReportInput reportInput = new ReportInput(); ReportInput reportInput = new ReportInput();
reportInput.setReportMetaData(reportMetaData); reportInput.setReportMetaData(reportMetaData);
reportInput.setReportDestination(new ReportDestination() reportInput.setReportDestination(new ReportDestination()
.withReportFormat(reportFormat) .withReportFormat(reportFormat)
.withReportOutputStream(reportOutputStream)); .withReportOutputStream(outputStream));
Map<String, Serializable> values = runBackendStepInput.getValues(); Map<String, Serializable> values = runBackendStepInput.getValues();
reportInput.setInputValues(values); reportInput.setInputValues(values);
new GenerateReportAction().execute(reportInput); new GenerateReportAction().execute(reportInput);
}
String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, savedReport);
runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + "." + reportFormat.getExtension()); runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + "." + reportFormat.getExtension());
runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath()); runBackendStepOutput.addValue("storageTableName", storageTableName);
runBackendStepOutput.addValue("storageReference", storageReference);
} }
catch(Exception e) catch(Exception e)
{ {

View File

@ -47,6 +47,9 @@ public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterf
{ {
public static final String NAME = "renderSavedReport"; public static final String NAME = "renderSavedReport";
public static final String FIELD_NAME_STORAGE_TABLE_NAME = "storageTableName";
public static final String FIELD_NAME_REPORT_FORMAT = "reportFormat";
/******************************************************************************* /*******************************************************************************
@ -61,13 +64,14 @@ public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterf
.withIcon(new QIcon().withName("print")) .withIcon(new QIcon().withName("print"))
.addStep(new QBackendStepMetaData() .addStep(new QBackendStepMetaData()
.withName("pre") .withName("pre")
.withInputData(new QFunctionInputMetaData().withRecordListMetaData(new QRecordListMetaData() .withInputData(new QFunctionInputMetaData()
.withTableName(SavedReport.TABLE_NAME))) .withField(new QFieldMetaData(FIELD_NAME_STORAGE_TABLE_NAME, QFieldType.STRING))
.withRecordListMetaData(new QRecordListMetaData().withTableName(SavedReport.TABLE_NAME)))
.withCode(new QCodeReference(RenderSavedReportPreStep.class))) .withCode(new QCodeReference(RenderSavedReportPreStep.class)))
.addStep(new QFrontendStepMetaData() .addStep(new QFrontendStepMetaData()
.withName("input") .withName("input")
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM)) .withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM))
.withFormField(new QFieldMetaData("reportFormat", QFieldType.STRING) .withFormField(new QFieldMetaData(FIELD_NAME_REPORT_FORMAT, QFieldType.STRING)
.withPossibleValueSourceName(ReportFormatPossibleValueEnum.NAME) .withPossibleValueSourceName(ReportFormatPossibleValueEnum.NAME)
.withIsRequired(true))) .withIsRequired(true)))
.addStep(new QBackendStepMetaData() .addStep(new QBackendStepMetaData()

View File

@ -22,10 +22,17 @@
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports; package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
import java.util.List;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/******************************************************************************* /*******************************************************************************
@ -40,8 +47,30 @@ public class RenderSavedReportPreStep implements BackendStep
@Override @Override
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{ {
// todo - verify ran on 1 String storageTableName = runBackendStepInput.getValueString(RenderSavedReportMetaDataProducer.FIELD_NAME_STORAGE_TABLE_NAME);
// todo - load the SavedReport if(!StringUtils.hasContent(storageTableName))
{
throw (new QUserFacingException("Process configuration error: Missing value for storageTableName."));
}
if(QContext.getQInstance().getTable(storageTableName) == null)
{
throw (new QUserFacingException("Process configuration error: Unrecognized value for storageTableName - no table named [" + storageTableName + "] was found in the instance."));
}
List<QRecord> records = runBackendStepInput.getRecords();
if(!CollectionUtils.nullSafeHasContents(records))
{
throw (new QUserFacingException("No report was selected or found to be rendered."));
}
if(records.size() > 1)
{
throw (new QUserFacingException("You may only render 1 report at a time."));
}
SavedReport savedReport = new SavedReport(records.get(0));
// todo - check for inputs - set up the input screen... // todo - check for inputs - set up the input screen...
} }

View File

@ -23,6 +23,9 @@ package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
@ -42,14 +45,17 @@ import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTa
import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableValue; import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableValue;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
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.storage.StorageInput;
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.savedreports.ReportColumns; import com.kingsrook.qqq.backend.core.model.savedreports.ReportColumns;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport; import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReportsMetaDataProvider; import com.kingsrook.qqq.backend.core.model.savedreports.SavedReportsMetaDataProvider;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryStorageAction;
import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.LocalMacDevUtils; import com.kingsrook.qqq.backend.core.utils.LocalMacDevUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.TestUtils; import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -57,7 +63,6 @@ import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/******************************************************************************* /*******************************************************************************
@ -71,7 +76,7 @@ class RenderSavedReportProcessTest extends BaseTest
@BeforeEach @BeforeEach
void beforeEach() throws Exception void beforeEach() throws Exception
{ {
new SavedReportsMetaDataProvider().defineAll(QContext.getQInstance(), TestUtils.MEMORY_BACKEND_NAME, null); new SavedReportsMetaDataProvider().defineAll(QContext.getQInstance(), TestUtils.MEMORY_BACKEND_NAME, TestUtils.MEMORY_BACKEND_NAME, null);
GenerateReportActionTest.insertPersonRecords(QContext.getQInstance()); GenerateReportActionTest.insertPersonRecords(QContext.getQInstance());
} }
@ -131,17 +136,14 @@ class RenderSavedReportProcessTest extends BaseTest
RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.CSV); RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.CSV);
String downloadFileName = runProcessOutput.getValueString("downloadFileName"); String downloadFileName = runProcessOutput.getValueString("downloadFileName");
String serverFilePath = runProcessOutput.getValueString("serverFilePath");
assertThat(downloadFileName) assertThat(downloadFileName)
.startsWith(label + " - ") .startsWith(label + " - ")
.matches(".*\\d\\d\\d\\d-\\d\\d-\\d\\d-\\d\\d\\d\\d.*") .matches(".*\\d\\d\\d\\d-\\d\\d-\\d\\d-\\d\\d\\d\\d.*")
.endsWith(".csv"); .endsWith(".csv");
File serverFile = new File(serverFilePath); InputStream inputStream = getInputStream(runProcessOutput);
assertTrue(serverFile.exists()); List<String> lines = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
List<String> lines = FileUtils.readLines(serverFile);
assertEquals(""" assertEquals("""
"Id","First Name","Last Name" "Id","First Name","Last Name"
""".trim(), lines.get(0)); """.trim(), lines.get(0));
@ -149,7 +151,41 @@ class RenderSavedReportProcessTest extends BaseTest
"1","Darin","Jonson" "1","Darin","Jonson"
""".trim(), lines.get(1)); """.trim(), lines.get(1));
LocalMacDevUtils.openFile(serverFilePath); writeTmpFileAndOpen(inputStream, ".csv");
}
/*******************************************************************************
**
*******************************************************************************/
private static InputStream getInputStream(RunProcessOutput runProcessOutput) throws QException
{
String storageTableName = runProcessOutput.getValueString("storageTableName");
String storageReference = runProcessOutput.getValueString("storageReference");
InputStream inputStream = new MemoryStorageAction().getInputStream(new StorageInput(storageTableName).withReference(storageReference));
return inputStream;
}
/*******************************************************************************
**
*******************************************************************************/
private void writeTmpFileAndOpen(InputStream inputStream, String suffix) throws IOException
{
// LocalMacDevUtils.mayOpenFiles = true;
if(LocalMacDevUtils.mayOpenFiles)
{
inputStream.reset();
File tmpFile = File.createTempFile(getClass().getName(), suffix, new File("/tmp/"));
FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
inputStream.transferTo(fileOutputStream);
fileOutputStream.close();
LocalMacDevUtils.openFile(tmpFile.getAbsolutePath());
}
} }
@ -203,14 +239,8 @@ class RenderSavedReportProcessTest extends BaseTest
QRecord savedReport = insertBasicSavedPivotReport(label); QRecord savedReport = insertBasicSavedPivotReport(label);
RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.XLSX); RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.XLSX);
String serverFilePath = runProcessOutput.getValueString("serverFilePath"); InputStream inputStream = getInputStream(runProcessOutput);
System.out.println(serverFilePath); writeTmpFileAndOpen(inputStream, ".xlsx");
File serverFile = new File(serverFilePath);
assertTrue(serverFile.exists());
LocalMacDevUtils.mayOpenFiles = true;
LocalMacDevUtils.openFile(serverFilePath, "/Applications/Numbers.app");
} }
@ -225,14 +255,9 @@ class RenderSavedReportProcessTest extends BaseTest
QRecord savedReport = insertBasicSavedPivotReport(label); QRecord savedReport = insertBasicSavedPivotReport(label);
RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.JSON); RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.JSON);
String serverFilePath = runProcessOutput.getValueString("serverFilePath"); InputStream inputStream = getInputStream(runProcessOutput);
System.out.println(serverFilePath); String json = StringUtils.join("\n", IOUtils.readLines(inputStream, StandardCharsets.UTF_8));
printReport(json);
File serverFile = new File(serverFilePath);
assertTrue(serverFile.exists());
String json = FileUtils.readFileToString(serverFile, StandardCharsets.UTF_8);
System.out.println(json);
JSONArray jsonArray = new JSONArray(json); JSONArray jsonArray = new JSONArray(json);
assertEquals(2, jsonArray.length()); assertEquals(2, jsonArray.length());
@ -262,6 +287,16 @@ class RenderSavedReportProcessTest extends BaseTest
/*******************************************************************************
**
*******************************************************************************/
private void printReport(String report)
{
// System.out.println(report);
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -272,13 +307,8 @@ class RenderSavedReportProcessTest extends BaseTest
QRecord savedReport = insertBasicSavedPivotReport(label); QRecord savedReport = insertBasicSavedPivotReport(label);
RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.CSV); RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.CSV);
String serverFilePath = runProcessOutput.getValueString("serverFilePath"); InputStream inputStream = getInputStream(runProcessOutput);
System.out.println(serverFilePath); List<String> csv = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
File serverFile = new File(serverFilePath);
assertTrue(serverFile.exists());
List<String> csv = FileUtils.readLines(serverFile, StandardCharsets.UTF_8);
System.out.println(csv); System.out.println(csv);
assertEquals(""" assertEquals("""
@ -316,6 +346,7 @@ class RenderSavedReportProcessTest extends BaseTest
} }
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -329,12 +360,8 @@ class RenderSavedReportProcessTest extends BaseTest
String serverFilePath = runProcessOutput.getValueString("serverFilePath"); String serverFilePath = runProcessOutput.getValueString("serverFilePath");
System.out.println(serverFilePath); System.out.println(serverFilePath);
File serverFile = new File(serverFilePath); InputStream inputStream = getInputStream(runProcessOutput);
assertTrue(serverFile.exists()); writeTmpFileAndOpen(inputStream, ".xlsx");
// LocalMacDevUtils.mayOpenFiles = true;
LocalMacDevUtils.openFile(serverFilePath, "/Applications/Numbers.app");
LocalMacDevUtils.openFile(serverFilePath);
} }
@ -349,13 +376,8 @@ class RenderSavedReportProcessTest extends BaseTest
QRecord savedReport = insertSavedPivotReportWithAllFunctions(label); QRecord savedReport = insertSavedPivotReportWithAllFunctions(label);
RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.CSV); RunProcessOutput runProcessOutput = runRenderReportProcess(savedReport, ReportFormatPossibleValueEnum.CSV);
String serverFilePath = runProcessOutput.getValueString("serverFilePath"); InputStream inputStream = getInputStream(runProcessOutput);
System.out.println(serverFilePath); List<String> csv = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
File serverFile = new File(serverFilePath);
assertTrue(serverFile.exists());
List<String> csv = FileUtils.readLines(serverFile, StandardCharsets.UTF_8);
System.out.println(csv); System.out.println(csv);
assertEquals(""" assertEquals("""

View File

@ -23,7 +23,7 @@ package com.kingsrook.qqq.backend.module.rdbms.reporting;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory; import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallbackFactory;
@ -44,6 +44,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy; 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.actions.tables.storage.StorageInput;
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.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportDataSource; import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportDataSource;
@ -55,11 +56,12 @@ import com.kingsrook.qqq.backend.core.model.savedreports.ReportColumns;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport; import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReportsMetaDataProvider; import com.kingsrook.qqq.backend.core.model.savedreports.SavedReportsMetaDataProvider;
import com.kingsrook.qqq.backend.core.model.session.QSession; import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryStorageAction;
import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.RenderSavedReportMetaDataProducer; import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.RenderSavedReportMetaDataProducer;
import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.module.rdbms.TestUtils; import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSActionTest; import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSActionTest;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
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;
@ -220,7 +222,7 @@ public class GenerateReportActionRDBMSTest extends RDBMSActionTest
{ {
newSavedReport.setLabel("Test Report"); newSavedReport.setLabel("Test Report");
QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_STORE_ALL_ACCESS, true)); QContext.setQSession(new QSession().withSecurityKeyValue(TestUtils.SECURITY_KEY_STORE_ALL_ACCESS, true));
new SavedReportsMetaDataProvider().defineAll(QContext.getQInstance(), TestUtils.MEMORY_BACKEND_NAME, null); new SavedReportsMetaDataProvider().defineAll(QContext.getQInstance(), TestUtils.MEMORY_BACKEND_NAME, TestUtils.MEMORY_BACKEND_NAME, null);
QRecord savedReport = new InsertAction().execute(new InsertInput(SavedReport.TABLE_NAME).withRecordEntity(newSavedReport)).getRecords().get(0); QRecord savedReport = new InsertAction().execute(new InsertInput(SavedReport.TABLE_NAME).withRecordEntity(newSavedReport)).getRecords().get(0);
@ -231,7 +233,11 @@ public class GenerateReportActionRDBMSTest extends RDBMSActionTest
input.addValue("reportFormat", ReportFormatPossibleValueEnum.CSV.getPossibleValueId()); input.addValue("reportFormat", ReportFormatPossibleValueEnum.CSV.getPossibleValueId());
RunProcessOutput runProcessOutput = new RunProcessAction().execute(input); RunProcessOutput runProcessOutput = new RunProcessAction().execute(input);
return (FileUtils.readLines(new File(runProcessOutput.getValueString("serverFilePath")), StandardCharsets.UTF_8)); String storageTableName = runProcessOutput.getValueString("storageTableName");
String storageReference = runProcessOutput.getValueString("storageReference");
InputStream inputStream = new MemoryStorageAction().getInputStream(new StorageInput(storageTableName).withReference(storageReference));
return (IOUtils.readLines(inputStream, StandardCharsets.UTF_8));
} }