Browse Source

update 优化调用树生成过程

add 支持查看调用节点详情
pull/3/head
yupi 2 years ago
parent
commit
667585f10c
5 changed files with 66 additions and 33 deletions
  1. +4
    -2
      README.md
  2. +3
    -2
      src/App.vue
  3. +31
    -7
      src/components/SearchableTree.vue
  4. +27
    -22
      src/generator/index.ts
  5. +1
    -0
      src/generator/type.d.ts

+ 4
- 2
README.md View File

@@ -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 语句的调用树和替换详情,便于分析引用关系


## 文档 ## 文档




+ 3
- 2
src/App.vue View File

@@ -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>


+ 31
- 7
src/components/SearchableTree.vue View File

@@ -13,13 +13,37 @@
:tree-data="tree" :tree-data="tree"
@expand="onExpand" @expand="onExpand"
> >
<template #title="{ title }">
<span v-if="title.indexOf(searchValue) > -1">
{{ title.substr(0, title.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
</span>
<span v-else>{{ title }}</span>
<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">
{{ title.substr(0, title.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
</span>
<span v-else>{{ title }}</span>
</a-popover>
</template> </template>
</a-tree> </a-tree>
</div> </div>


+ 27
- 22
src/generator/index.ts View File

@@ -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);
return replaceSubSql(result, context, invokeTreeNode);
let childInvokeTreeNode: InvokeTreeNode | undefined;
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(
replacementNode,
context,
params,
childInvokeTreeNode
);
const replacement = generateSQL(subKey, context, params, invokeTreeNode);
result = result.replace(regExpMatchArray[0], replacement); result = result.replace(regExpMatchArray[0], replacement);
regExpMatchArray = matchSubQuery(result); regExpMatchArray = matchSubQuery(result);
} }


+ 1
- 0
src/generator/type.d.ts View File

@@ -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