Validate chart business block datasets
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
package com.ruoyi.generator.service.front;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.generator.domain.GenTable;
|
||||
import com.ruoyi.generator.domain.GenTableColumn;
|
||||
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockDefinition;
|
||||
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockInstance;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartDatasetConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartDateRangeConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartDimensionConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartFilterConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartMetricConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartSortConfig;
|
||||
|
||||
public class ChartDatasetValidator
|
||||
{
|
||||
public static final String DATASET_SCHEMA = "single-table-aggregate-v1";
|
||||
|
||||
private static final Set<String> CHART_TYPES =
|
||||
new HashSet<String>(Arrays.asList("metric", "line", "bar", "pie"));
|
||||
private static final Set<String> AGGREGATES =
|
||||
new HashSet<String>(Arrays.asList("count", "sum", "avg"));
|
||||
private static final Set<String> TIME_UNITS =
|
||||
new HashSet<String>(Arrays.asList("day", "week", "month"));
|
||||
private static final Set<String> OPERATORS =
|
||||
new HashSet<String>(Arrays.asList(
|
||||
"eq", "ne", "gt", "gte", "lt", "lte", "between", "in", "is_null", "is_not_null"));
|
||||
private static final Set<String> DATE_PRESETS =
|
||||
new HashSet<String>(Arrays.asList(
|
||||
"today", "last_7_days", "last_30_days", "this_month", "this_year", "fixed"));
|
||||
private static final Set<Integer> SPANS =
|
||||
new HashSet<Integer>(Arrays.asList(Integer.valueOf(12), Integer.valueOf(6), Integer.valueOf(4)));
|
||||
private static final Pattern ALIAS_PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9_]{0,39}");
|
||||
|
||||
public void validate(BusinessBlockDefinition definition, BusinessBlockInstance instance, List<GenTable> tables)
|
||||
{
|
||||
if (definition == null || instance == null)
|
||||
{
|
||||
throw new ServiceException("图表业务块配置不存在");
|
||||
}
|
||||
String blockName = StringUtils.defaultIfEmpty(instance.getName(), definition.getName());
|
||||
ChartDatasetConfig dataset = instance.getDataset();
|
||||
if (dataset == null)
|
||||
{
|
||||
throw error(blockName, "数据集配置缺失");
|
||||
}
|
||||
|
||||
String expectedSchema = StringUtils.defaultIfEmpty(definition.getDatasetSchema(), DATASET_SCHEMA);
|
||||
if (!expectedSchema.equals(dataset.getSchema()))
|
||||
{
|
||||
throw error(blockName, "数据集协议必须为 " + expectedSchema);
|
||||
}
|
||||
|
||||
GenTable table = requireTable(blockName, dataset.getTable(), tables);
|
||||
validateSpan(definition, instance, blockName);
|
||||
|
||||
String chartType = StringUtils.defaultString(definition.getChartType()).toLowerCase();
|
||||
if (!CHART_TYPES.contains(chartType))
|
||||
{
|
||||
throw error(blockName, "未知图表类型:" + chartType);
|
||||
}
|
||||
|
||||
validateDimension(blockName, chartType, dataset.getDimension(), table);
|
||||
Set<String> aliases = validateMetrics(blockName, chartType, dataset.getMetrics(), table);
|
||||
validateFilters(blockName, dataset.getFilters(), table);
|
||||
validateDateRange(blockName, dataset.getDateRange(), table);
|
||||
validateSort(blockName, dataset.getSort(), aliases);
|
||||
validateLimit(blockName, chartType, dataset);
|
||||
}
|
||||
|
||||
private void validateSpan(BusinessBlockDefinition definition, BusinessBlockInstance instance, String blockName)
|
||||
{
|
||||
if (instance.getSpan() == null)
|
||||
{
|
||||
Integer defaultSpan = definition.getDefaultSpan();
|
||||
instance.setSpan(SPANS.contains(defaultSpan) ? defaultSpan : Integer.valueOf(12));
|
||||
}
|
||||
if (!SPANS.contains(instance.getSpan()))
|
||||
{
|
||||
throw error(blockName, "宽度只能为 12、6 或 4");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDimension(String blockName, String chartType, ChartDimensionConfig dimension, GenTable table)
|
||||
{
|
||||
if ("metric".equals(chartType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (dimension == null || StringUtils.isEmpty(dimension.getField()))
|
||||
{
|
||||
throw error(blockName, "请选择维度字段");
|
||||
}
|
||||
GenTableColumn column = requireColumn(blockName, table, dimension.getField());
|
||||
String timeUnit = StringUtils.defaultString(dimension.getTimeUnit()).toLowerCase();
|
||||
if (StringUtils.isEmpty(timeUnit))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!TIME_UNITS.contains(timeUnit))
|
||||
{
|
||||
throw error(blockName, "时间粒度只能为 day、week 或 month");
|
||||
}
|
||||
if (!isTemporal(column))
|
||||
{
|
||||
throw error(blockName, "字段 " + dimension.getField() + " 不是时间类型,不能设置时间粒度");
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> validateMetrics(String blockName, String chartType, List<ChartMetricConfig> metrics,
|
||||
GenTable table)
|
||||
{
|
||||
List<ChartMetricConfig> safeMetrics = metrics == null
|
||||
? Collections.<ChartMetricConfig>emptyList() : metrics;
|
||||
int size = safeMetrics.size();
|
||||
if (("metric".equals(chartType) || "pie".equals(chartType)) && size != 1)
|
||||
{
|
||||
throw error(blockName, "指标卡和饼图必须配置 1 个指标");
|
||||
}
|
||||
if (("line".equals(chartType) || "bar".equals(chartType)) && (size < 1 || size > 3))
|
||||
{
|
||||
throw error(blockName, "折线图和柱状图必须配置 1 到 3 个指标");
|
||||
}
|
||||
|
||||
Set<String> aliases = new HashSet<String>();
|
||||
for (ChartMetricConfig metric : safeMetrics)
|
||||
{
|
||||
if (metric == null)
|
||||
{
|
||||
throw error(blockName, "指标配置不能为空");
|
||||
}
|
||||
String aggregate = StringUtils.defaultString(metric.getAggregate()).toLowerCase();
|
||||
if (!AGGREGATES.contains(aggregate))
|
||||
{
|
||||
throw error(blockName, "未知聚合方式:" + aggregate);
|
||||
}
|
||||
GenTableColumn column = null;
|
||||
if (StringUtils.isNotEmpty(metric.getField()))
|
||||
{
|
||||
column = requireColumn(blockName, table, metric.getField());
|
||||
}
|
||||
else if (!"count".equals(aggregate))
|
||||
{
|
||||
throw error(blockName, aggregate.toUpperCase() + " 必须选择指标字段");
|
||||
}
|
||||
if (("sum".equals(aggregate) || "avg".equals(aggregate)) && !isNumeric(column))
|
||||
{
|
||||
throw error(blockName, "指标字段 " + metric.getField() + " 不是数值类型,不能使用 "
|
||||
+ aggregate.toUpperCase());
|
||||
}
|
||||
|
||||
String alias = StringUtils.defaultString(metric.getAlias());
|
||||
if (!ALIAS_PATTERN.matcher(alias).matches())
|
||||
{
|
||||
throw error(blockName, "指标别名必须以字母开头,且只能包含字母、数字和下划线");
|
||||
}
|
||||
if (!aliases.add(alias))
|
||||
{
|
||||
throw error(blockName, "指标别名不能重复:" + alias);
|
||||
}
|
||||
}
|
||||
return aliases;
|
||||
}
|
||||
|
||||
private void validateFilters(String blockName, List<ChartFilterConfig> filters, GenTable table)
|
||||
{
|
||||
List<ChartFilterConfig> safeFilters = filters == null
|
||||
? Collections.<ChartFilterConfig>emptyList() : filters;
|
||||
if (safeFilters.size() > 10)
|
||||
{
|
||||
throw error(blockName, "筛选条件不能超过 10 个");
|
||||
}
|
||||
for (ChartFilterConfig filter : safeFilters)
|
||||
{
|
||||
if (filter == null)
|
||||
{
|
||||
throw error(blockName, "筛选条件不能为空");
|
||||
}
|
||||
requireColumn(blockName, table, filter.getField());
|
||||
String operator = StringUtils.defaultString(filter.getOperator()).toLowerCase();
|
||||
if (!OPERATORS.contains(operator))
|
||||
{
|
||||
throw error(blockName, "未知筛选运算符:" + operator);
|
||||
}
|
||||
validateFilterValue(blockName, operator, filter.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateFilterValue(String blockName, String operator, Object value)
|
||||
{
|
||||
if ("is_null".equals(operator) || "is_not_null".equals(operator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ("between".equals(operator))
|
||||
{
|
||||
if (valueCount(value) != 2)
|
||||
{
|
||||
throw error(blockName, "between 筛选必须提供两个值");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ("in".equals(operator))
|
||||
{
|
||||
if (valueCount(value) < 1)
|
||||
{
|
||||
throw error(blockName, "in 筛选至少提供一个值");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
|
||||
{
|
||||
throw error(blockName, operator + " 筛选必须提供值");
|
||||
}
|
||||
}
|
||||
|
||||
private int valueCount(Object value)
|
||||
{
|
||||
if (value instanceof Collection)
|
||||
{
|
||||
return ((Collection<?>) value).size();
|
||||
}
|
||||
if (value != null && value.getClass().isArray())
|
||||
{
|
||||
return Array.getLength(value);
|
||||
}
|
||||
return value == null ? 0 : 1;
|
||||
}
|
||||
|
||||
private void validateDateRange(String blockName, ChartDateRangeConfig dateRange, GenTable table)
|
||||
{
|
||||
if (dateRange == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
GenTableColumn column = requireColumn(blockName, table, dateRange.getField());
|
||||
if (!isTemporal(column))
|
||||
{
|
||||
throw error(blockName, "日期范围字段 " + dateRange.getField() + " 不是时间类型");
|
||||
}
|
||||
String preset = StringUtils.defaultString(dateRange.getPreset()).toLowerCase();
|
||||
if (!DATE_PRESETS.contains(preset))
|
||||
{
|
||||
throw error(blockName, "未知日期范围:" + preset);
|
||||
}
|
||||
if ("fixed".equals(preset)
|
||||
&& (StringUtils.isEmpty(dateRange.getStart()) || StringUtils.isEmpty(dateRange.getEnd())))
|
||||
{
|
||||
throw error(blockName, "固定日期范围必须提供开始和结束日期");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSort(String blockName, ChartSortConfig sort, Set<String> aliases)
|
||||
{
|
||||
if (sort == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
String by = StringUtils.defaultString(sort.getBy());
|
||||
if (!"dimension".equals(by) && !aliases.contains(by))
|
||||
{
|
||||
throw error(blockName, "排序字段必须为 dimension 或已配置的指标别名");
|
||||
}
|
||||
String order = StringUtils.defaultString(sort.getOrder()).toLowerCase();
|
||||
if (!"asc".equals(order) && !"desc".equals(order))
|
||||
{
|
||||
throw error(blockName, "排序方向只能为 asc 或 desc");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLimit(String blockName, String chartType, ChartDatasetConfig dataset)
|
||||
{
|
||||
if (dataset.getLimit() == null)
|
||||
{
|
||||
dataset.setLimit(Integer.valueOf(defaultLimit(chartType)));
|
||||
}
|
||||
if (dataset.getLimit().intValue() < 1 || dataset.getLimit().intValue() > 500)
|
||||
{
|
||||
throw error(blockName, "分组上限必须在 1 到 500 之间");
|
||||
}
|
||||
}
|
||||
|
||||
private int defaultLimit(String chartType)
|
||||
{
|
||||
if ("metric".equals(chartType)) return 1;
|
||||
if ("pie".equals(chartType)) return 10;
|
||||
if ("bar".equals(chartType)) return 20;
|
||||
return 100;
|
||||
}
|
||||
|
||||
private GenTable requireTable(String blockName, String tableName, List<GenTable> tables)
|
||||
{
|
||||
Map<String, GenTable> tableMap = new LinkedHashMap<String, GenTable>();
|
||||
for (GenTable table : tables == null ? Collections.<GenTable>emptyList() : tables)
|
||||
{
|
||||
if (table != null && StringUtils.isNotEmpty(table.getTableName()))
|
||||
{
|
||||
tableMap.put(table.getTableName(), table);
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(tableName) || !tableMap.containsKey(tableName))
|
||||
{
|
||||
throw error(blockName, "数据表不存在:" + StringUtils.defaultString(tableName));
|
||||
}
|
||||
return tableMap.get(tableName);
|
||||
}
|
||||
|
||||
private GenTableColumn requireColumn(String blockName, GenTable table, String fieldName)
|
||||
{
|
||||
for (GenTableColumn column : table.getColumns() == null
|
||||
? Collections.<GenTableColumn>emptyList() : table.getColumns())
|
||||
{
|
||||
if (column != null && (StringUtils.equals(fieldName, column.getColumnName())
|
||||
|| StringUtils.equals(fieldName, column.getJavaField())))
|
||||
{
|
||||
return column;
|
||||
}
|
||||
}
|
||||
throw error(blockName, "字段不存在:" + table.getTableName() + "." + StringUtils.defaultString(fieldName));
|
||||
}
|
||||
|
||||
private boolean isNumeric(GenTableColumn column)
|
||||
{
|
||||
return column != null && StringUtils.equalsAnyIgnoreCase(column.getJavaType(),
|
||||
"Integer", "Long", "Double", "Float", "Short", "BigDecimal");
|
||||
}
|
||||
|
||||
private boolean isTemporal(GenTableColumn column)
|
||||
{
|
||||
if (column == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
String columnType = StringUtils.defaultString(column.getColumnType()).toLowerCase();
|
||||
return StringUtils.equalsAnyIgnoreCase(column.getJavaType(), "Date", "LocalDate", "LocalDateTime")
|
||||
|| columnType.contains("date")
|
||||
|| columnType.contains("time")
|
||||
|| columnType.contains("timestamp")
|
||||
|| columnType.contains("year");
|
||||
}
|
||||
|
||||
private ServiceException error(String blockName, String message)
|
||||
{
|
||||
return new ServiceException("图表“" + StringUtils.defaultString(blockName) + "”" + message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
package com.ruoyi.generator.service.front;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.generator.domain.GenTable;
|
||||
import com.ruoyi.generator.domain.GenTableColumn;
|
||||
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockDefinition;
|
||||
import com.ruoyi.generator.domain.front.dto.block.BusinessBlockInstance;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartDatasetConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartDimensionConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartFilterConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartMetricConfig;
|
||||
import com.ruoyi.generator.domain.front.dto.block.ChartSortConfig;
|
||||
|
||||
public class ChartDatasetValidatorTest
|
||||
{
|
||||
private final ChartDatasetValidator validator = new ChartDatasetValidator();
|
||||
|
||||
@Test
|
||||
public void chartValidationAcceptsSingleTableTimeSeries()
|
||||
{
|
||||
validator.validate(lineChartDefinition(), validLineChartInstance(), chartTables());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsSumOnTextField()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
instance.getDataset().getMetrics().get(0).setField("status");
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("SUM"));
|
||||
assertTrue(exception.getMessage().contains("status"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsInvalidSpan()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
instance.setSpan(Integer.valueOf(5));
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("宽度"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsMoreThanThreeMetrics()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
instance.getDataset().setMetrics(Arrays.asList(
|
||||
metric("amount", "sum", "metric1"),
|
||||
metric("amount", "avg", "metric2"),
|
||||
metric("id", "count", "metric3"),
|
||||
metric("amount", "sum", "metric4")));
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("1 到 3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsMoreThanTenFilters()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
List<ChartFilterConfig> filters = new ArrayList<ChartFilterConfig>();
|
||||
for (int i = 0; i < 11; i++)
|
||||
{
|
||||
filters.add(filter("status", "eq", "PAID"));
|
||||
}
|
||||
instance.getDataset().setFilters(filters);
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("10"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsInvalidTimeUnit()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
instance.getDataset().getDimension().setTimeUnit("quarter");
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("时间粒度"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsUnknownFilterOperator()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
instance.getDataset().setFilters(Collections.singletonList(filter("status", "contains_sql", "PAID")));
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("运算符"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsDuplicateMetricAliases()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
instance.getDataset().setMetrics(Arrays.asList(
|
||||
metric("amount", "sum", "metric1"),
|
||||
metric("amount", "avg", "metric1")));
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("别名"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chartValidationRejectsLimitAboveFiveHundred()
|
||||
{
|
||||
BusinessBlockInstance instance = validLineChartInstance();
|
||||
instance.getDataset().setLimit(Integer.valueOf(501));
|
||||
|
||||
ServiceException exception = expectServiceException(() ->
|
||||
validator.validate(lineChartDefinition(), instance, chartTables()));
|
||||
|
||||
assertTrue(exception.getMessage().contains("500"));
|
||||
}
|
||||
|
||||
private BusinessBlockDefinition lineChartDefinition()
|
||||
{
|
||||
BusinessBlockDefinition definition = new BusinessBlockDefinition();
|
||||
definition.setCode("admin_line_chart");
|
||||
definition.setName("折线图");
|
||||
definition.setKind("chart");
|
||||
definition.setChartType("line");
|
||||
definition.setDatasetSchema("single-table-aggregate-v1");
|
||||
definition.setSurfaces(Collections.singletonList("admin"));
|
||||
definition.setPlacements(Arrays.asList("embedded", "page"));
|
||||
definition.setDefaultSpan(Integer.valueOf(12));
|
||||
return definition;
|
||||
}
|
||||
|
||||
private BusinessBlockInstance validLineChartInstance()
|
||||
{
|
||||
BusinessBlockInstance instance = new BusinessBlockInstance();
|
||||
instance.setId("admin_line_chart_001");
|
||||
instance.setBlockCode("admin_line_chart");
|
||||
instance.setName("近 30 天销售趋势");
|
||||
instance.setSpan(Integer.valueOf(6));
|
||||
|
||||
ChartDimensionConfig dimension = new ChartDimensionConfig();
|
||||
dimension.setField("create_time");
|
||||
dimension.setTimeUnit("day");
|
||||
|
||||
ChartDatasetConfig dataset = new ChartDatasetConfig();
|
||||
dataset.setSchema("single-table-aggregate-v1");
|
||||
dataset.setTable("shop_order");
|
||||
dataset.setDimension(dimension);
|
||||
dataset.setMetrics(Collections.singletonList(metric("amount", "sum", "salesAmount")));
|
||||
dataset.setFilters(Collections.singletonList(filter("status", "eq", "PAID")));
|
||||
ChartSortConfig sort = new ChartSortConfig();
|
||||
sort.setBy("dimension");
|
||||
sort.setOrder("asc");
|
||||
dataset.setSort(sort);
|
||||
dataset.setLimit(Integer.valueOf(100));
|
||||
instance.setDataset(dataset);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ChartMetricConfig metric(String field, String aggregate, String alias)
|
||||
{
|
||||
ChartMetricConfig metric = new ChartMetricConfig();
|
||||
metric.setField(field);
|
||||
metric.setAggregate(aggregate);
|
||||
metric.setAlias(alias);
|
||||
metric.setLabel(alias);
|
||||
return metric;
|
||||
}
|
||||
|
||||
private ChartFilterConfig filter(String field, String operator, Object value)
|
||||
{
|
||||
ChartFilterConfig filter = new ChartFilterConfig();
|
||||
filter.setField(field);
|
||||
filter.setOperator(operator);
|
||||
filter.setValue(value);
|
||||
return filter;
|
||||
}
|
||||
|
||||
private List<GenTable> chartTables()
|
||||
{
|
||||
GenTable table = new GenTable();
|
||||
table.setTableName("shop_order");
|
||||
table.setColumns(Arrays.asList(
|
||||
typedColumn("id", "id", "Long", "bigint"),
|
||||
typedColumn("amount", "amount", "BigDecimal", "decimal(10,2)"),
|
||||
typedColumn("status", "status", "String", "varchar(32)"),
|
||||
typedColumn("create_time", "createTime", "Date", "datetime")));
|
||||
return Collections.singletonList(table);
|
||||
}
|
||||
|
||||
private GenTableColumn typedColumn(String columnName, String javaField, String javaType, String columnType)
|
||||
{
|
||||
GenTableColumn column = new GenTableColumn();
|
||||
column.setColumnName(columnName);
|
||||
column.setJavaField(javaField);
|
||||
column.setJavaType(javaType);
|
||||
column.setColumnType(columnType);
|
||||
return column;
|
||||
}
|
||||
|
||||
private ServiceException expectServiceException(ThrowingRunnable runnable)
|
||||
{
|
||||
try
|
||||
{
|
||||
runnable.run();
|
||||
}
|
||||
catch (ServiceException e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
throw new AssertionError("Expected ServiceException");
|
||||
}
|
||||
|
||||
private interface ThrowingRunnable
|
||||
{
|
||||
void run();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user