mirror of
https://github.com/vran-dev/databasir.git
synced 2025-09-17 17:16:56 +08:00
fix: replace new line symbol to <br/> in exported markdown (#265)
This commit is contained in:
@@ -3,13 +3,9 @@ package com.databasir.core;
|
||||
import com.databasir.core.meta.data.DatabaseMeta;
|
||||
import com.databasir.core.meta.provider.MetaProviders;
|
||||
import com.databasir.core.meta.provider.condition.Condition;
|
||||
import com.databasir.core.render.Render;
|
||||
import com.databasir.core.render.RenderConfig;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -41,14 +37,6 @@ public class Databasir {
|
||||
.select(connection, condition);
|
||||
}
|
||||
|
||||
public void renderAsMarkdown(DatabaseMeta meta, OutputStream out) throws IOException {
|
||||
renderAsMarkdown(new RenderConfig(), meta, out);
|
||||
}
|
||||
|
||||
public void renderAsMarkdown(RenderConfig config, DatabaseMeta meta, OutputStream stream) throws IOException {
|
||||
Render.markdownRender(config).rendering(meta, stream);
|
||||
}
|
||||
|
||||
public static Databasir of() {
|
||||
return of(new DatabasirConfig());
|
||||
}
|
||||
|
@@ -1,17 +0,0 @@
|
||||
package com.databasir.core.render;
|
||||
|
||||
import com.databasir.core.meta.data.DatabaseMeta;
|
||||
import com.databasir.core.render.markdown.MarkdownTemplateRender;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface Render {
|
||||
|
||||
void rendering(DatabaseMeta meta, OutputStream outputStream) throws IOException;
|
||||
|
||||
static Render markdownRender(RenderConfig configuration) {
|
||||
return new MarkdownTemplateRender(configuration);
|
||||
}
|
||||
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
package com.databasir.core.render;
|
||||
|
||||
import com.databasir.core.meta.data.ColumnMeta;
|
||||
import com.databasir.core.meta.data.IndexMeta;
|
||||
import com.databasir.core.meta.data.TriggerMeta;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Data
|
||||
public class RenderConfig {
|
||||
|
||||
private Boolean renderTables = true;
|
||||
|
||||
private Boolean renderColumns = true;
|
||||
|
||||
private Boolean renderIndexes = true;
|
||||
|
||||
private Boolean renderTriggers = true;
|
||||
|
||||
private LinkedHashMap<String, Function<ColumnMeta, String>> columnTitleAndValueMapping =
|
||||
columnTitleAndValueMapping();
|
||||
|
||||
private LinkedHashMap<String, Function<IndexMeta, String>> indexTitleAndValueMapping =
|
||||
indexTitleAndValueMapping();
|
||||
|
||||
private LinkedHashMap<String, Function<TriggerMeta, String>> triggerTitleAndValueMapping =
|
||||
triggerTitleAndValueMapping();
|
||||
|
||||
protected LinkedHashMap<String, Function<ColumnMeta, String>> columnTitleAndValueMapping() {
|
||||
LinkedHashMap<String, Function<ColumnMeta, String>> mapping = new LinkedHashMap<>();
|
||||
mapping.put("Name", ColumnMeta::getName);
|
||||
mapping.put("Type", column -> {
|
||||
String type;
|
||||
if (column.getDecimalDigits() == null || column.getDecimalDigits().equals(0)) {
|
||||
type = column.getType()
|
||||
+ "(" + column.getSize().toString() + ")";
|
||||
} else {
|
||||
type = column.getType()
|
||||
+ "(" + column.getSize().toString() + ", " + column.getDecimalDigits().toString() + ")";
|
||||
}
|
||||
return type;
|
||||
});
|
||||
return mapping;
|
||||
}
|
||||
|
||||
protected LinkedHashMap<String, Function<IndexMeta, String>> indexTitleAndValueMapping() {
|
||||
LinkedHashMap<String, Function<IndexMeta, String>> mapping = new LinkedHashMap<>();
|
||||
mapping.put("Name", IndexMeta::getName);
|
||||
mapping.put("IsUnique", index -> index.getIsUniqueKey() ? "YES" : "");
|
||||
mapping.put("Columns", index -> String.join(", ", index.getColumnNames()));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
protected LinkedHashMap<String, Function<TriggerMeta, String>> triggerTitleAndValueMapping() {
|
||||
LinkedHashMap<String, Function<TriggerMeta, String>> mapping = new LinkedHashMap<>();
|
||||
mapping.put("Name", TriggerMeta::getName);
|
||||
mapping.put("Timing", trigger -> trigger.getTiming() + " " + trigger.getManipulation());
|
||||
mapping.put("Statement", trigger -> trigger.getStatement().replace("\n", " ")
|
||||
.replace("\r", " "));
|
||||
mapping.put("Create At", TriggerMeta::getCreateAt);
|
||||
return mapping;
|
||||
}
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
package com.databasir.core.render.markdown;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MarkdownBuilder {
|
||||
|
||||
private static final String LINE = "\n";
|
||||
|
||||
private static final String DOUBLE_LINE = LINE + LINE;
|
||||
|
||||
private StringBuilder builder = new StringBuilder(1024);
|
||||
|
||||
private MarkdownBuilder() {
|
||||
}
|
||||
|
||||
public static MarkdownBuilder builder() {
|
||||
return new MarkdownBuilder();
|
||||
}
|
||||
|
||||
public MarkdownBuilder primaryTitle(String title) {
|
||||
builder.append("# ").append(title).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder secondTitle(String title) {
|
||||
builder.append("## ").append(title).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder thirdTitle(String title) {
|
||||
builder.append("### ").append(title).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder text(String text) {
|
||||
builder.append(text).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder table(List<String> titles, List<List<String>> rows) {
|
||||
if (titles == null || titles.isEmpty()) {
|
||||
throw new IllegalArgumentException("titles must not be null or empty");
|
||||
}
|
||||
// build titles
|
||||
builder.append("| ");
|
||||
for (String title : titles) {
|
||||
builder.append(title).append(" | ");
|
||||
}
|
||||
builder.append(LINE);
|
||||
|
||||
// build separators
|
||||
builder.append("| ");
|
||||
for (String title : titles) {
|
||||
builder.append("------").append(" | ");
|
||||
}
|
||||
builder.append(LINE);
|
||||
|
||||
// build rows
|
||||
for (List<String> row : rows) {
|
||||
builder.append("| ");
|
||||
for (String column : row) {
|
||||
builder.append(column).append(" | ");
|
||||
}
|
||||
builder.append(LINE);
|
||||
}
|
||||
builder.append(LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder orderedList(List<String> list) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
builder.append(i + 1).append(". ").append(list.get(i)).append(LINE);
|
||||
}
|
||||
builder.append(LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder unorderedList(List<String> list) {
|
||||
for (String item : list) {
|
||||
builder.append("- ").append(item).append(LINE);
|
||||
}
|
||||
builder.append(LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder blockquotes(String content) {
|
||||
builder.append("> ").append(content).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder code(String languageType, String statement) {
|
||||
builder.append("```").append(languageType).append(LINE)
|
||||
.append(statement)
|
||||
.append("```")
|
||||
.append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder link(String text, String link) {
|
||||
builder.append("[").append(text).append("]")
|
||||
.append("(").append(link).append(")");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String build() {
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -1,114 +0,0 @@
|
||||
package com.databasir.core.render.markdown;
|
||||
|
||||
import com.databasir.core.meta.data.DatabaseMeta;
|
||||
import com.databasir.core.meta.data.TableMeta;
|
||||
import com.databasir.core.render.Render;
|
||||
import com.databasir.core.render.RenderConfig;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MarkdownRender implements Render {
|
||||
|
||||
@Getter
|
||||
private final RenderConfig config;
|
||||
|
||||
protected MarkdownRender(RenderConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public static MarkdownRender of(RenderConfig config) {
|
||||
return new MarkdownRender(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rendering(DatabaseMeta meta,
|
||||
OutputStream outputStream) throws IOException {
|
||||
MarkdownBuilder contentBuilder = MarkdownBuilder.builder();
|
||||
contentBuilder.primaryTitle(meta.getDatabaseName());
|
||||
if (config.getRenderTables()) {
|
||||
for (TableMeta table : meta.getTables()) {
|
||||
buildTableName(contentBuilder, table);
|
||||
if (config.getRenderColumns()) {
|
||||
buildColumns(contentBuilder, table);
|
||||
}
|
||||
if (config.getRenderIndexes()) {
|
||||
buildIndexes(contentBuilder, table);
|
||||
}
|
||||
if (config.getRenderTriggers()) {
|
||||
buildTriggers(contentBuilder, table);
|
||||
}
|
||||
}
|
||||
}
|
||||
outputStream.write(contentBuilder.build().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private void buildTableName(MarkdownBuilder contentBuilder, TableMeta table) {
|
||||
String tableName;
|
||||
if (table.getComment().isEmpty()) {
|
||||
tableName = table.getName();
|
||||
} else {
|
||||
tableName = table.getName() + "(" + table.getComment() + ")";
|
||||
}
|
||||
contentBuilder.secondTitle(tableName);
|
||||
}
|
||||
|
||||
private void buildColumns(MarkdownBuilder contentBuilder, TableMeta table) {
|
||||
contentBuilder.unorderedList(Collections.singletonList("columns"));
|
||||
List<List<String>> allColumnRows = table.getColumns()
|
||||
.stream()
|
||||
.map(column -> config.getColumnTitleAndValueMapping()
|
||||
.values()
|
||||
.stream()
|
||||
.map(mapping -> mapping.apply(column))
|
||||
.collect(Collectors.toList()))
|
||||
.collect(Collectors.toList());
|
||||
contentBuilder.table(tableTitles(), allColumnRows);
|
||||
}
|
||||
|
||||
private void buildIndexes(MarkdownBuilder contentBuilder, TableMeta table) {
|
||||
contentBuilder.unorderedList(Collections.singletonList("indexes"));
|
||||
List<List<String>> allIndexRows = table.getIndexes().stream()
|
||||
.map(index -> config.getIndexTitleAndValueMapping()
|
||||
.values()
|
||||
.stream()
|
||||
.map(mapping -> mapping.apply(index))
|
||||
.collect(Collectors.toList()))
|
||||
.collect(Collectors.toList());
|
||||
contentBuilder.table(indexTitles(), allIndexRows);
|
||||
}
|
||||
|
||||
private void buildTriggers(MarkdownBuilder contentBuilder, TableMeta table) {
|
||||
if (table.getTriggers() == null || table.getTriggers().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
contentBuilder.unorderedList(Collections.singletonList("triggers"));
|
||||
List<List<String>> allRows = table.getTriggers().stream()
|
||||
.map(trigger -> config.getTriggerTitleAndValueMapping()
|
||||
.values()
|
||||
.stream()
|
||||
.map(mapping -> mapping.apply(trigger))
|
||||
.collect(Collectors.toList()))
|
||||
.collect(Collectors.toList());
|
||||
contentBuilder.table(triggerTitles(), allRows);
|
||||
}
|
||||
|
||||
private List<String> tableTitles() {
|
||||
return new ArrayList<>(config.getColumnTitleAndValueMapping().keySet());
|
||||
}
|
||||
|
||||
private List<String> indexTitles() {
|
||||
return new ArrayList<>(config.getIndexTitleAndValueMapping().keySet());
|
||||
}
|
||||
|
||||
private List<String> triggerTitles() {
|
||||
return new ArrayList<>(config.getTriggerTitleAndValueMapping().keySet());
|
||||
}
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
package com.databasir.core.render.markdown;
|
||||
|
||||
import com.databasir.core.meta.data.DatabaseMeta;
|
||||
import com.databasir.core.render.Render;
|
||||
import com.databasir.core.render.RenderConfig;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
import freemarker.template.TemplateExceptionHandler;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* use freemarker template to render markdown
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class MarkdownTemplateRender implements Render {
|
||||
|
||||
private final RenderConfig renderConfig;
|
||||
|
||||
private String templatePath = "template/render/markdown/markdown.ftlh";
|
||||
|
||||
public MarkdownTemplateRender(RenderConfig config, String templatePath) {
|
||||
this(config);
|
||||
this.templatePath = templatePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rendering(DatabaseMeta meta, OutputStream outputStream) throws IOException {
|
||||
doRendering(meta, outputStream);
|
||||
}
|
||||
|
||||
public void doRendering(DatabaseMeta meta, OutputStream outputStream) throws IOException {
|
||||
Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
|
||||
cfg.setClassForTemplateLoading(getClass(), "/");
|
||||
cfg.setDefaultEncoding("UTF-8");
|
||||
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||
cfg.setLogTemplateExceptions(false);
|
||||
cfg.setWrapUncheckedExceptions(true);
|
||||
cfg.setFallbackOnNullLoopVariable(false);
|
||||
|
||||
Map<String, Object> root = new HashMap<>();
|
||||
root.put("meta", meta);
|
||||
root.put("config", renderConfig);
|
||||
Template template = cfg.getTemplate(templatePath);
|
||||
try {
|
||||
template.process(root, new OutputStreamWriter(outputStream));
|
||||
} catch (TemplateException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
# ${meta.databaseName}
|
||||
| | |
|
||||
| --------------- | ---- |
|
||||
| Database name | |
|
||||
| Product name | |
|
||||
| Product version | |
|
||||
|
||||
## Overview
|
||||
| | name | type | comment |
|
||||
| ---- | --------------- | ------ | ------ |
|
||||
<#list meta.tables as table>
|
||||
| ${table_index+1} | [${table.name}](#${table.name}) | ${table.type} | ${table.comment!'N/A'} |
|
||||
</#list>
|
||||
|
||||
<#if config.renderTables>
|
||||
<#list meta.tables as table>
|
||||
## ${table.name}
|
||||
<#if config.renderColumns>
|
||||
### Columns
|
||||
|
||||
| | name | type | primary Key | nullable | auto increment| default | comment |
|
||||
| --- | ---- | ---- | ----------- | -------- | ------------- | ------- | ------- |
|
||||
<#list table.columns as column>
|
||||
| ${column_index+1} | ${column.name} | ${column.type} | ${column.isPrimaryKey?then('YES','NO')} | ${column.nullable } | ${column.autoIncrement} | ${column.defaultValue!'NULL'} | ${column.comment!''} |
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if config.renderIndexes>
|
||||
### Indexes
|
||||
|
||||
| | name | unique | columns |
|
||||
| --- | ---- | ------ | ------- |
|
||||
<#list table.indexes as index>
|
||||
| ${index_index+1} | ${index.name} | ${index.isUniqueKey?then('YES', 'NO')} | ${index.columnNames?join(', ')} |
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<#if config.renderTriggers>
|
||||
### Triggers
|
||||
|
||||
| | name | timing | statement | created |
|
||||
| --- | ---- | ------ | --------- | ------- |
|
||||
<#list table.triggers as trigger>
|
||||
| ${trigger_index} | ${trigger.name} | ${trigger.timing + " " + trigger.manipulation } | ${trigger.statement?replace("\n", "<br>")?replace("\r", " ")} | ${trigger.createAt} |
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
</#list>
|
||||
</#if>
|
Reference in New Issue
Block a user