feat(new-tool): added an SQL prettifier and formatter

This commit is contained in:
Corentin Thomasset 2022-07-24 14:37:27 +02:00
parent 6cd25a743e
commit d1f95f5b34
No known key found for this signature in database
GPG key ID: DBD997E935996158
7 changed files with 169 additions and 5 deletions

26
package-lock.json generated
View file

@ -30,6 +30,7 @@
"plausible-tracker": "^0.3.5", "plausible-tracker": "^0.3.5",
"qrcode": "^1.5.0", "qrcode": "^1.5.0",
"randombytes": "^2.1.0", "randombytes": "^2.1.0",
"sql-formatter": "^8.2.0",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"vue": "^3.2.31", "vue": "^3.2.31",
"vue-router": "^4.0.12" "vue-router": "^4.0.12"
@ -3089,8 +3090,7 @@
"node_modules/argparse": { "node_modules/argparse": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
"dev": true
}, },
"node_modules/array-ify": { "node_modules/array-ify": {
"version": "1.0.0", "version": "1.0.0",
@ -9580,6 +9580,17 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true "dev": true
}, },
"node_modules/sql-formatter": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-8.2.0.tgz",
"integrity": "sha512-5hQOSOk8jfhPkNgUmpm+9Fn2aaLWcf4vKL/dIvUN5q9rsamKHSyN/gL79xpkETNOyL+Zv5BMQfA7z9Rmz/DJJg==",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"sql-formatter": "bin/sql-formatter-cli.js"
}
},
"node_modules/stable": { "node_modules/stable": {
"version": "0.1.8", "version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
@ -13660,8 +13671,7 @@
"argparse": { "argparse": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
"dev": true
}, },
"array-ify": { "array-ify": {
"version": "1.0.0", "version": "1.0.0",
@ -18502,6 +18512,14 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true "dev": true
}, },
"sql-formatter": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-8.2.0.tgz",
"integrity": "sha512-5hQOSOk8jfhPkNgUmpm+9Fn2aaLWcf4vKL/dIvUN5q9rsamKHSyN/gL79xpkETNOyL+Zv5BMQfA7z9Rmz/DJJg==",
"requires": {
"argparse": "^2.0.1"
}
},
"stable": { "stable": {
"version": "0.1.8", "version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",

View file

@ -52,6 +52,7 @@
"plausible-tracker": "^0.3.5", "plausible-tracker": "^0.3.5",
"qrcode": "^1.5.0", "qrcode": "^1.5.0",
"randombytes": "^2.1.0", "randombytes": "^2.1.0",
"sql-formatter": "^8.2.0",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"vue": "^3.2.31", "vue": "^3.2.31",
"vue-router": "^4.0.12" "vue-router": "^4.0.12"

View file

@ -21,6 +21,7 @@ import { tool as mathEvaluator } from './math-evaluator';
import { tool as qrCodeGenerator } from './qr-code-generator'; import { tool as qrCodeGenerator } from './qr-code-generator';
import { tool as randomPortGenerator } from './random-port-generator'; import { tool as randomPortGenerator } from './random-port-generator';
import { tool as romanNumeralConverter } from './roman-numeral-converter'; import { tool as romanNumeralConverter } from './roman-numeral-converter';
import { tool as sqlPrettify } from './sql-prettify';
import { tool as textStatistics } from './text-statistics'; import { tool as textStatistics } from './text-statistics';
import { tool as tokenGenerator } from './token-generator'; import { tool as tokenGenerator } from './token-generator';
import { tool as urlEncoder } from './url-encoder'; import { tool as urlEncoder } from './url-encoder';
@ -53,7 +54,7 @@ export const toolsByCategory: ToolCategory[] = [
{ {
name: 'Development', name: 'Development',
icon: LockOpen, icon: LockOpen,
components: [gitMemo, randomPortGenerator, crontabGenerator, jsonViewer], components: [gitMemo, randomPortGenerator, crontabGenerator, jsonViewer, sqlPrettify],
}, },
{ {
name: 'Math', name: 'Math',

View file

@ -0,0 +1,26 @@
import { Database } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'SQL prettify and format',
path: '/sql-prettify',
description: 'Format and prettify your SQL queries online (it supports various SQL dialects).',
keywords: [
'sql',
'prettify',
'beautify',
'GCP BigQuery',
'IBM DB2',
'Apache Hive',
'MariaDB',
'MySQL',
'Couchbase N1QL',
'Oracle PL/SQL',
'PostgreSQL',
'Amazon Redshift',
'Spark',
'SQL Server Transact-SQL',
],
component: () => import('./sql-prettify.vue'),
icon: Database,
});

View file

@ -0,0 +1,6 @@
import { expect, describe, it } from 'vitest';
// import { } from './sql-prettify.service';
//
// describe('sql-prettify', () => {
//
// })

View file

@ -0,0 +1,112 @@
<template>
<div style="flex: 0 0 100%">
<div style="margin: 0 auto; width: 600px">
<n-space n-space item-style="flex: 1 1 0">
<div>
<n-form-item label="Dialect">
<n-select
v-model:value="config.language"
:options="[
{ label: 'GCP BigQuery', value: 'bigquery' },
{ label: 'IBM DB2', value: 'db2' },
{ label: 'Apache Hive', value: 'hive' },
{ label: 'MariaDB', value: 'mariadb' },
{ label: 'MySQL', value: 'mysql' },
{ label: 'Couchbase N1QL', value: 'n1ql' },
{ label: 'Oracle PL/SQL', value: 'plsql' },
{ label: 'PostgreSQL', value: 'postgresql' },
{ label: 'Amazon Redshift', value: 'redshift' },
{ label: 'Spark', value: 'spark' },
{ label: 'Standard SQL', value: 'sql' },
{ label: 'sqlite', value: 'sqlite' },
{ label: 'SQL Server Transact-SQL', value: 'tsql' },
]"
/>
</n-form-item>
</div>
<div>
<n-form-item label="Keyword case">
<n-select
v-model:value="config.keywordCase"
:options="[
{ label: 'UPPERCASE', value: 'upper' },
{ label: 'lowercase', value: 'lower' },
{ label: 'Preserve', value: 'preserve' },
]"
/>
</n-form-item>
</div>
<div>
<n-form-item label="Indent style">
<n-select
v-model:value="config.indentStyle"
:options="[
{ label: 'Standard', value: 'standard' },
{ label: 'Tabular left', value: 'tabularLeft' },
{ label: 'Tabular right', value: 'tabularRight' },
]"
/>
</n-form-item>
</div>
</n-space>
</div>
</div>
<n-form-item label="Your SQL query">
<n-input
ref="inputElement"
v-model:value="rawSQL"
placeholder="Put your SQL query here..."
type="textarea"
rows="20"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
spellcheck="false"
/>
</n-form-item>
<n-form-item label="Prettify version of your query">
<n-card class="result-card" :style="`min-height: ${inputElementHeight ?? 400}px`">
<n-config-provider :hljs="hljs">
<n-code :code="prettySQL" language="sql" :trim="false" />
</n-config-provider>
<n-button v-if="prettySQL" class="copy-button" secondary @click="copy">Copy</n-button>
</n-card>
</n-form-item>
</template>
<script setup lang="ts">
import { useCopy } from '@/composable/copy';
import { useElementSize } from '@vueuse/core';
import hljs from 'highlight.js/lib/core';
import sqlHljs from 'highlight.js/lib/languages/sql';
import { format as formatSQL, type FormatFnOptions } from 'sql-formatter';
import { computed, reactive, ref } from 'vue';
hljs.registerLanguage('sql', sqlHljs);
const inputElement = ref<HTMLElement>();
const { height: inputElementHeight } = useElementSize(inputElement);
const config = reactive<Partial<FormatFnOptions>>({
keywordCase: 'upper',
useTabs: false,
language: 'sql',
indentStyle: 'standard',
tabulateAlias: true,
});
const rawSQL = ref('select field1,field2,field3 from my_table where my_condition;');
const prettySQL = computed(() => formatSQL(rawSQL.value, config));
const { copy } = useCopy({ source: prettySQL });
</script>
<style lang="less" scoped>
.result-card {
position: relative;
.copy-button {
position: absolute;
top: 10px;
right: 10px;
}
}
</style>