update 优化调用树生成过程

add 支持查看调用节点详情
pull/3/head
yupi 3 years ago
parent caac5af5cd
commit 667585f10c

@ -13,7 +13,9 @@
1. 将 SQL 的编写逻辑 `结构化` ,像写文章大纲一样编写和阅读 SQL 1. 将 SQL 的编写逻辑 `结构化` ,像写文章大纲一样编写和阅读 SQL
2. 重复的 SQL 只需编写一次 SQL 变动时修改一处即可 2. 重复的 SQL 只需编写一次 SQL 变动时修改一处即可
3. 可以针对某部分 SQL 进行传参和调试 3. 可以针对某部分 SQL 进行传参和调试
4. 查看 SQL 语句的引用树 4. 查看 SQL 语句的引用树和替换过程,便于分析理解 SQL
![查看调用树和替换过程](https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/1/image-20220514143425002.png)
## 应用场景 ## 应用场景
@ -63,7 +65,7 @@ from
3. 支持参数透传,比如 @a(xx = #{yy})yy 变量可传递给 @a 公式 3. 支持参数透传,比如 @a(xx = #{yy})yy 变量可传递给 @a 公式
4. 支持嵌套传参(将子查询作为参数),比如 @a(xx = @b(yy = 1)) 4. 支持嵌套传参(将子查询作为参数),比如 @a(xx = @b(yy = 1))
5. 不限制用户在 JSON 中编写的内容,因此该工具也可以作为重复代码生成器来使用 5. 不限制用户在 JSON 中编写的内容,因此该工具也可以作为重复代码生成器来使用
6. 支持查看 SQL 语句的调用树,便于分析引用关系 6. 支持查看 SQL 语句的调用树和替换详情,便于分析引用关系
## 文档 ## 文档

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { doGenerateSQL } from "./generator"; import { doGenerateSQL } from "./generator";
import { importExample } from "./examples"; import { importExample } from "./examples";
import { onMounted, ref, toRaw, watch } from "vue"; import { onMounted, ref, toRaw } from "vue";
import * as monaco from "monaco-editor"; import * as monaco from "monaco-editor";
import { format } from "sql-formatter"; import { format } from "sql-formatter";
import { GithubOutlined } from "@ant-design/icons-vue"; import { GithubOutlined } from "@ant-design/icons-vue";
@ -56,6 +56,7 @@ const getSQL = () => {
toRaw(outputEditor.value).setValue(result); toRaw(outputEditor.value).setValue(result);
// //
invokeTree.value = [generateResult.invokeTree]; invokeTree.value = [generateResult.invokeTree];
console.log(invokeTree.value);
}; };
const showInvokeTree = () => { const showInvokeTree = () => {
@ -120,7 +121,7 @@ onMounted(() => {
<a-button size="large" type="primary" ghost @click="showInvokeTree"> <a-button size="large" type="primary" ghost @click="showInvokeTree">
查看调用树 查看调用树
</a-button> </a-button>
<a-button size="large" type="default" @click="importExample"> <a-button size="large" type="default" @click="importExample('init')">
导入例子 导入例子
</a-button> </a-button>
</a-space> </a-space>

@ -13,13 +13,37 @@
:tree-data="tree" :tree-data="tree"
@expand="onExpand" @expand="onExpand"
> >
<template #title="{ title }"> <template #title="{ title, sql, params, resultSQL }">
<a-popover title="详情" placement="top">
<template #content>
<div style="max-width: 600px">
<p>
<b>替换前语句</b>
<a-typography-paragraph copyable>
{{ sql }}
</a-typography-paragraph>
</p>
<p>
<b>替换参数</b>
<a-typography-paragraph copyable>
{{ params ?? "无" }}
</a-typography-paragraph>
</p>
<p>
<b>替换后语句</b>
<a-typography-paragraph copyable>
{{ resultSQL }}
</a-typography-paragraph>
</p>
</div>
</template>
<span v-if="title.indexOf(searchValue) > -1"> <span v-if="title.indexOf(searchValue) > -1">
{{ title.substr(0, title.indexOf(searchValue)) }} {{ title.substr(0, title.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span> <span style="color: #f50">{{ searchValue }}</span>
{{ title.substr(title.indexOf(searchValue) + searchValue.length) }} {{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
</span> </span>
<span v-else>{{ title }}</span> <span v-else>{{ title }}</span>
</a-popover>
</template> </template>
</a-tree> </a-tree>
</div> </div>

@ -19,35 +19,55 @@ export function doGenerateSQL(json: InputJSON) {
const rootInvokeTreeNode = { ...initTreeNode }; const rootInvokeTreeNode = { ...initTreeNode };
const context = json; const context = json;
const resultSQL = generateSQL( const resultSQL = generateSQL(
context.main, "main",
context, context,
context.main?.params, context.main?.params,
rootInvokeTreeNode rootInvokeTreeNode
); );
return { return {
resultSQL, resultSQL,
invokeTree: rootInvokeTreeNode, invokeTree: rootInvokeTreeNode.children[0], // 取第一个作为根节点
}; };
} }
/** /**
* SQL * SQL
* @param currentNode * @param key
* @param context * @param context
* @param params * @param params
* @param invokeTreeNode * @param invokeTreeNode
*/ */
function generateSQL( function generateSQL(
currentNode: InputJSONValue, key: string,
context: InputJSON, context: InputJSON,
params?: Record<string, string>, params?: Record<string, string>,
invokeTreeNode?: InvokeTreeNode invokeTreeNode?: InvokeTreeNode
): string { ): string {
const currentNode = context[key];
if (!currentNode) { if (!currentNode) {
return ""; return "";
} }
const result = replaceParams(currentNode, context, params, invokeTreeNode); let childInvokeTreeNode: InvokeTreeNode | undefined;
return replaceSubSql(result, context, invokeTreeNode); if (invokeTreeNode) {
childInvokeTreeNode = {
title: key,
sql: currentNode.sql ?? currentNode,
params,
children: [],
};
invokeTreeNode.children?.push(childInvokeTreeNode);
}
const result = replaceParams(
currentNode,
context,
params,
childInvokeTreeNode
);
const resultSQL = replaceSubSql(result, context, childInvokeTreeNode);
if (childInvokeTreeNode) {
childInvokeTreeNode.resultSQL = resultSQL;
}
return resultSQL;
} }
/** /**
@ -140,23 +160,8 @@ function replaceSubSql(
const key = keyValueArray[0].trim(); const key = keyValueArray[0].trim();
params[key] = keyValueArray[1].trim(); params[key] = keyValueArray[1].trim();
} }
let childInvokeTreeNode;
if (invokeTreeNode) {
childInvokeTreeNode = {
title: subKey,
sql,
params,
children: [],
};
invokeTreeNode.children?.push(childInvokeTreeNode);
}
// 递归解析被替换节点 // 递归解析被替换节点
const replacement = generateSQL( const replacement = generateSQL(subKey, context, params, invokeTreeNode);
replacementNode,
context,
params,
childInvokeTreeNode
);
result = result.replace(regExpMatchArray[0], replacement); result = result.replace(regExpMatchArray[0], replacement);
regExpMatchArray = matchSubQuery(result); regExpMatchArray = matchSubQuery(result);
} }

@ -16,6 +16,7 @@ interface InvokeTreeNode {
sql: string; sql: string;
key?: string; key?: string;
params?: Record<string, string>; params?: Record<string, string>;
resultSQL?: string;
children?: InvokeTreeNode[]; children?: InvokeTreeNode[];
} }

Loading…
Cancel
Save