CE-881 - Initial checkin - saved report entity, meta-data, and process to generate.

This commit is contained in:
2024-03-27 20:07:53 -05:00
parent bd4f5f3633
commit 8bbbd02558
6 changed files with 907 additions and 0 deletions

View File

@ -0,0 +1,386 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.savedreports;
import java.time.Instant;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.data.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.fields.DynamicDefaultValueBehavior;
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
import com.kingsrook.qqq.backend.core.model.metadata.tables.TablesPossibleValueSourceMetaDataProvider;
/*******************************************************************************
** Entity bean for the saved report table
*******************************************************************************/
public class SavedReport extends QRecordEntity
{
public static final String TABLE_NAME = "savedReport";
@QField(isEditable = false)
private Integer id;
@QField(isEditable = false)
private Instant createDate;
@QField(isEditable = false)
private Instant modifyDate;
@QField(isRequired = true, maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String label;
@QField(possibleValueSourceName = TablesPossibleValueSourceMetaDataProvider.NAME, maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.ERROR)
private String tableName; // todo - qqqTableId... ?
@QField(maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.ERROR, dynamicDefaultValueBehavior = DynamicDefaultValueBehavior.USER_ID)
private String userId;
@QField(label = "Query Filter")
private String queryFilterJson;
@QField(label = "Columns")
private String columnsJson;
@QField(label = "Input Fields")
private String inputFieldsJson;
@QField(label = "Pivot Table")
private String pivotTableJson;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public SavedReport()
{
}
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public SavedReport(QRecord qRecord) throws QException
{
populateFromQRecord(qRecord);
}
/*******************************************************************************
** Getter for id
**
*******************************************************************************/
public Integer getId()
{
return id;
}
/*******************************************************************************
** Setter for id
**
*******************************************************************************/
public void setId(Integer id)
{
this.id = id;
}
/*******************************************************************************
** Getter for createDate
**
*******************************************************************************/
public Instant getCreateDate()
{
return createDate;
}
/*******************************************************************************
** Setter for createDate
**
*******************************************************************************/
public void setCreateDate(Instant createDate)
{
this.createDate = createDate;
}
/*******************************************************************************
** Getter for modifyDate
**
*******************************************************************************/
public Instant getModifyDate()
{
return modifyDate;
}
/*******************************************************************************
** Setter for modifyDate
**
*******************************************************************************/
public void setModifyDate(Instant modifyDate)
{
this.modifyDate = modifyDate;
}
/*******************************************************************************
** Getter for label
**
*******************************************************************************/
public String getLabel()
{
return label;
}
/*******************************************************************************
** Setter for label
**
*******************************************************************************/
public void setLabel(String label)
{
this.label = label;
}
/*******************************************************************************
** Fluent setter for label
**
*******************************************************************************/
public SavedReport withLabel(String label)
{
this.label = label;
return (this);
}
/*******************************************************************************
** Getter for tableName
**
*******************************************************************************/
public String getTableName()
{
return tableName;
}
/*******************************************************************************
** Setter for tableName
**
*******************************************************************************/
public void setTableName(String tableName)
{
this.tableName = tableName;
}
/*******************************************************************************
** Fluent setter for tableName
**
*******************************************************************************/
public SavedReport withTableName(String tableName)
{
this.tableName = tableName;
return (this);
}
/*******************************************************************************
** Getter for userId
**
*******************************************************************************/
public String getUserId()
{
return userId;
}
/*******************************************************************************
** Setter for userId
**
*******************************************************************************/
public void setUserId(String userId)
{
this.userId = userId;
}
/*******************************************************************************
** Fluent setter for userId
**
*******************************************************************************/
public SavedReport withUserId(String userId)
{
this.userId = userId;
return (this);
}
/*******************************************************************************
** Getter for queryFilterJson
*******************************************************************************/
public String getQueryFilterJson()
{
return (this.queryFilterJson);
}
/*******************************************************************************
** Setter for queryFilterJson
*******************************************************************************/
public void setQueryFilterJson(String queryFilterJson)
{
this.queryFilterJson = queryFilterJson;
}
/*******************************************************************************
** Fluent setter for queryFilterJson
*******************************************************************************/
public SavedReport withQueryFilterJson(String queryFilterJson)
{
this.queryFilterJson = queryFilterJson;
return (this);
}
/*******************************************************************************
** Getter for columnsJson
*******************************************************************************/
public String getColumnsJson()
{
return (this.columnsJson);
}
/*******************************************************************************
** Setter for columnsJson
*******************************************************************************/
public void setColumnsJson(String columnsJson)
{
this.columnsJson = columnsJson;
}
/*******************************************************************************
** Fluent setter for columnsJson
*******************************************************************************/
public SavedReport withColumnsJson(String columnsJson)
{
this.columnsJson = columnsJson;
return (this);
}
/*******************************************************************************
** Getter for inputFieldsJson
*******************************************************************************/
public String getInputFieldsJson()
{
return (this.inputFieldsJson);
}
/*******************************************************************************
** Setter for inputFieldsJson
*******************************************************************************/
public void setInputFieldsJson(String inputFieldsJson)
{
this.inputFieldsJson = inputFieldsJson;
}
/*******************************************************************************
** Fluent setter for inputFieldsJson
*******************************************************************************/
public SavedReport withInputFieldsJson(String inputFieldsJson)
{
this.inputFieldsJson = inputFieldsJson;
return (this);
}
/*******************************************************************************
** Getter for pivotTableJson
*******************************************************************************/
public String getPivotTableJson()
{
return (this.pivotTableJson);
}
/*******************************************************************************
** Setter for pivotTableJson
*******************************************************************************/
public void setPivotTableJson(String pivotTableJson)
{
this.pivotTableJson = pivotTableJson;
}
/*******************************************************************************
** Fluent setter for pivotTableJson
*******************************************************************************/
public SavedReport withPivotTableJson(String pivotTableJson)
{
this.pivotTableJson = pivotTableJson;
return (this);
}
}

View File

@ -0,0 +1,101 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.model.savedreports;
import java.util.List;
import java.util.function.Consumer;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
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.layout.QIcon;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
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.Tier;
import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.RenderSavedReportMetaDataProducer;
/*******************************************************************************
**
*******************************************************************************/
public class SavedReportsMetaDataProvider
{
/*******************************************************************************
**
*******************************************************************************/
public void defineAll(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
{
instance.addTable(defineSavedReportTable(backendName, backendDetailEnricher));
instance.addPossibleValueSource(defineSavedReportPossibleValueSource());
instance.addProcess(new RenderSavedReportMetaDataProducer().produce(instance));
}
/*******************************************************************************
**
*******************************************************************************/
public QTableMetaData defineSavedReportTable(String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
{
QTableMetaData table = new QTableMetaData()
.withName(SavedReport.TABLE_NAME)
.withLabel("Saved Report")
.withIcon(new QIcon().withName("article"))
.withRecordLabelFormat("%s")
.withRecordLabelFields("label")
.withBackendName(backendName)
.withPrimaryKeyField("id")
.withFieldsFromEntity(SavedReport.class)
.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("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("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));
for(String jsonFieldName : List.of("queryFilterJson", "columnsJson", "inputFieldsJson", "pivotTableJson"))
{
table.getField(jsonFieldName).withFieldAdornment(new FieldAdornment(AdornmentType.CODE_EDITOR).withValue(AdornmentType.CodeEditorValues.languageMode("json")));
}
if(backendDetailEnricher != null)
{
backendDetailEnricher.accept(table);
}
return (table);
}
/*******************************************************************************
**
*******************************************************************************/
private QPossibleValueSource defineSavedReportPossibleValueSource()
{
return QPossibleValueSource.newForTable(SavedReport.TABLE_NAME);
}
}

View File

@ -0,0 +1,110 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
import java.io.File;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction;
import com.kingsrook.qqq.backend.core.exceptions.QException;
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.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.metadata.reporting.QReportMetaData;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
**
*******************************************************************************/
public class RenderSavedReportExecuteStep implements BackendStep
{
/*******************************************************************************
**
*******************************************************************************/
@Override
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{
try
{
SavedReport savedReport = new SavedReport(runBackendStepInput.getRecords().get(0));
File tmpFile = File.createTempFile("SavedReport" + savedReport.getId(), ".xlsx", new File("/tmp/"));
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
QReportMetaData reportMetaData = new SavedReportToReportMetaDataAdapter().adapt(savedReport);
try(FileOutputStream reportOutputStream = new FileOutputStream(tmpFile))
{
ReportInput reportInput = new ReportInput();
reportInput.setReportMetaData(reportMetaData);
reportInput.setReportDestination(new ReportDestination()
.withReportFormat(ReportFormat.XLSX) // todo - variable
.withReportOutputStream(reportOutputStream));
Map<String, Serializable> values = runBackendStepInput.getValues();
reportInput.setInputValues(values);
new GenerateReportAction().execute(reportInput);
}
String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, savedReport);
runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + ".xlsx");
runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath());
}
catch(Exception e)
{
// todo - render error screen?
}
}
/*******************************************************************************
**
*******************************************************************************/
private String getDownloadFileBaseName(RunBackendStepInput runBackendStepInput, SavedReport report)
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HHmm").withZone(ZoneId.systemDefault());
String datePart = formatter.format(Instant.now());
String downloadFileBaseName = runBackendStepInput.getValueString("downloadFileBaseName");
if(!StringUtils.hasContent(downloadFileBaseName))
{
downloadFileBaseName = report.getLabel();
}
downloadFileBaseName = downloadFileBaseName.replaceAll("/", "-");
return (downloadFileBaseName + " - " + datePart);
}
}

View File

@ -0,0 +1,79 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface;
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.layout.QIcon;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QComponentType;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
/*******************************************************************************
**
*******************************************************************************/
public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterface<QProcessMetaData>
{
public static final String NAME = "renderSavedReport";
/*******************************************************************************
**
*******************************************************************************/
@Override
public QProcessMetaData produce(QInstance qInstance) throws QException
{
QProcessMetaData process = new QProcessMetaData()
.withName(NAME)
.withTableName(SavedReport.TABLE_NAME)
.withIcon(new QIcon().withName("print"))
.addStep(new QBackendStepMetaData()
.withName("pre")
.withInputData(new QFunctionInputMetaData().withRecordListMetaData(new QRecordListMetaData()
.withTableName(SavedReport.TABLE_NAME)))
.withCode(new QCodeReference(RenderSavedReportPreStep.class)))
.addStep(new QFrontendStepMetaData()
.withName("input")
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM)))
.addStep(new QBackendStepMetaData()
.withName("execute")
.withInputData(new QFunctionInputMetaData().withRecordListMetaData(new QRecordListMetaData()
.withTableName(SavedReport.TABLE_NAME)))
.withCode(new QCodeReference(RenderSavedReportExecuteStep.class)))
// todo - no no, stream the damn thing... how to do that??
.addStep(new QFrontendStepMetaData()
.withName("output")
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.DOWNLOAD_FORM)));
return (process);
}
}

View File

@ -0,0 +1,48 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
/*******************************************************************************
**
*******************************************************************************/
public class RenderSavedReportPreStep implements BackendStep
{
/*******************************************************************************
**
*******************************************************************************/
@Override
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{
// todo - verify ran on 1
// todo - load the SavedReport
// todo - check for inputs - set up the input screen...
}
}

View File

@ -0,0 +1,183 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2024. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableDefinition;
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.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportDataSource;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportField;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
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.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
import com.kingsrook.qqq.backend.core.utils.collections.ListBuilder;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
**
*******************************************************************************/
public class SavedReportToReportMetaDataAdapter
{
private static final QLogger LOG = QLogger.getLogger(SavedReportToReportMetaDataAdapter.class);
/*******************************************************************************
**
*******************************************************************************/
public QReportMetaData adapt(SavedReport savedReport) throws QException
{
try
{
QReportMetaData reportMetaData = new QReportMetaData();
reportMetaData.setLabel(savedReport.getLabel());
////////////////////////////
// set up the data-source //
////////////////////////////
QReportDataSource dataSource = new QReportDataSource();
reportMetaData.setDataSources(List.of(dataSource));
dataSource.setName("main");
QTableMetaData table = QContext.getQInstance().getTable(savedReport.getTableName());
dataSource.setSourceTable(savedReport.getTableName());
dataSource.setQueryFilter(JsonUtils.toObject(savedReport.getQueryFilterJson(), QQueryFilter.class));
// todo!!! oh my.
List<QueryJoin> queryJoins = null;
dataSource.setQueryJoins(queryJoins);
//////////////////////////
// set up the main view //
//////////////////////////
QReportView view = new QReportView();
reportMetaData.setViews(ListBuilder.of(view));
view.setName("main");
view.setType(ReportType.TABLE);
view.setDataSourceName(dataSource.getName());
view.setLabel(savedReport.getLabel()); // todo eh?
view.setIncludeHeaderRow(true);
// don't need:
// view.setOrderByFields(); - only used for summary reports
// view.setTitleFormat(); - not using at this time
// view.setTitleFields(); - not using at this time
// view.setRecordTransformStep();
// view.setViewCustomizer();
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// columns in the saved-report look like a JSON object, w/ a key "columns", which is an array of objects //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
Map<String, Object> columnsObject = JsonUtils.toObject(savedReport.getColumnsJson(), new TypeReference<>() {});
List<Map<String, Object>> columns = (List<Map<String, Object>>) columnsObject.get("columns");
List<QReportField> reportColumns = new ArrayList<>();
for(Map<String, Object> column : columns)
{
if(column.containsKey("isVisible") && !"true".equals(ValueUtils.getValueAsString(column.get("isVisible"))))
{
continue;
}
QFieldMetaData field = null;
String fieldName = ValueUtils.getValueAsString(column.get("name"));
if(fieldName.contains("."))
{
// todo - join!
}
else
{
field = table.getFields().get(fieldName);
if(field == null)
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// frontend may often pass __checked__ (or maybe other __ prefixes in the future - so - don't warn that. //
///////////////////////////////////////////////////////////////////////////////////////////////////////////
if(!fieldName.startsWith("__"))
{
LOG.warn("Saved Report has an unexpected unrecognized field name", logPair("savedReportId", savedReport.getId()), logPair("table", table.getName()), logPair("fieldName", fieldName));
}
continue;
}
}
QReportField reportField = new QReportField();
reportColumns.add(reportField);
reportField.setName(fieldName);
reportField.setLabel(field.getLabel());
if(StringUtils.hasContent(field.getPossibleValueSourceName()))
{
reportField.setShowPossibleValueLabel(true);
}
}
view.setColumns(reportColumns);
///////////////////////////////////////////////
// if it's a pivot report, add that view too //
///////////////////////////////////////////////
if(StringUtils.hasContent(savedReport.getPivotTableJson()))
{
QReportView pivotView = new QReportView();
reportMetaData.getViews().add(pivotView);
pivotView.setName("pivot"); // does this appear?
pivotView.setType(ReportType.PIVOT);
pivotView.setPivotTableSourceViewName(view.getName());
pivotView.setPivotTableDefinition(JsonUtils.toObject(savedReport.getPivotTableJson(), PivotTableDefinition.class));
}
/////////////////////////////////////////////////////
// add input fields, if they're in the savedReport //
/////////////////////////////////////////////////////
if(StringUtils.hasContent(savedReport.getInputFieldsJson()))
{
reportMetaData.setInputFields(JsonUtils.toObject(savedReport.getInputFieldsJson(), new TypeReference<>() {}));
}
return (reportMetaData);
}
catch(Exception e)
{
LOG.warn("Error adapting savedReport to reportMetaData", e, logPair("savedReportId", savedReport.getId()));
throw (new QException("Error adapting savedReport to reportMetaData", e));
}
}
}