Skip to content

Commit

Permalink
[5.x] Enhance query preview when using the pgsql driver (#1486)
Browse files Browse the repository at this point in the history
* Use the frameworks query grammar formatting when using laravel >= 10.x

* Change highlighting based on sql dialect

* Fix styleci and add an assertion for setting the driver name

* Update Highligter.vue

---------

Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
morloderex and taylorotwell authored Jun 17, 2024
1 parent 8e145db commit 1394592
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 62 deletions.
119 changes: 101 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
"resolve-url-loader": "^5.0.0",
"sass": "^1.15.2",
"sass-loader": "^11.0.1",
"sql-formatter": "^3.1.0",
"sql-formatter": "^15.3.1",
"vue": "^2.5.7",
"vue-copy-to-clipboard": "^1.0.3",
"vue-json-pretty": "^1.6.2",
"vue-loader": "^15.9.6",
"vue-router": "^3.0.1",
"vue-template-compiler": "^2.5.21",
"vue-copy-to-clipboard": "^1.0.3"
"vue-template-compiler": "^2.5.21"
}
}
2 changes: 1 addition & 1 deletion public/app.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/mix-manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"/app.js": "/app.js?id=7049e92a398e816f8cd53a915eaea592",
"/app.js": "/app.js?id=9a52c14de3847c3cc640ff1845ef3ed0",
"/app-dark.css": "/app-dark.css?id=1ea407db56c5163ae29311f1f38eb7b9",
"/app.css": "/app.css?id=de4c978567bfd90b38d186937dee5ccf"
}
1 change: 1 addition & 0 deletions resources/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Vue.component('index-screen', require('./components/IndexScreen.vue').default);
Vue.component('preview-screen', require('./components/PreviewScreen.vue').default);
Vue.component('alert', require('./components/Alert.vue').default);
Vue.component('copy-clipboard', require('./components/CopyClipboard.vue').default);
Vue.component('higlighter', require('./components/Highligter.vue').default);

Vue.mixin(Base);

Expand Down
68 changes: 68 additions & 0 deletions resources/js/components/Highligter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<script type="text/ecmascript-6">
import hljs from 'highlight.js/lib/core';
import sql from 'highlight.js/lib/languages/sql';
import pgsql from 'highlight.js/lib/languages/pgsql'
hljs.registerLanguage('sql', sql)
hljs.registerLanguage('pgsql', pgsql)
function hasValueOrEmptyAttribute(value) {
return Boolean(value || value === "");
}
function escapeHTML(value) {
return value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;');
}
export default {
props: ["language", "code", "autodetect"],
data: function() {
return {
detectedLanguage: "",
unknownLanguage: false
};
},
computed: {
className() {
if (this.unknownLanguage) return "";
return "hljs " + this.detectedLanguage;
},
highlighted() {
if (!this.autoDetect && !hljs.getLanguage(this.language)) {
console.warn(`The language "${this.language}" you specified could not be found.`);
this.unknownLanguage = true;
return escapeHTML(this.code);
}
let result = {};
if (this.autoDetect) {
result = hljs.highlightAuto(this.code);
this.detectedLanguage = result.language;
} else {
result = hljs.highlight(this.code, { language: this.language, ignoreIllegals: this.ignoreIllegals });
this.detectedLanguage = this.language;
}
return result.value;
},
autoDetect() {
return ! this.language || hasValueOrEmptyAttribute(this.autodetect);
},
ignoreIllegals() {
return true;
}
},
template: `<pre><code :class="className" v-html="highlighted"></code></pre>`
};
</script>
50 changes: 36 additions & 14 deletions resources/js/screens/queries/preview.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
<script type="text/ecmascript-6">
import hljs from 'highlight.js/lib/core';
import sql from 'highlight.js/lib/languages/sql';
import { format } from 'sql-formatter';
hljs.registerLanguage('sql', sql);
import { format } from 'sql-formatter';
export default {
methods: {
highlightSQL() {
this.$nextTick(() => {
hljs.highlightElement(this.$refs.sqlcode);
});
formatSql(sql, language) {
return format(sql, { language: this.mapLanguage(language)});
},
mapLanguage(language) {
if (language === 'sql') {
return language;
}
switch (language) {
case 'pgsql':
return 'postgresql';
case 'mysql':
return 'mysql';
case 'mariadb':
return 'mariadb'
case 'sqlite':
return 'sqlite'
case 'sqlsrv':
return 'transactsql'
}
},
formatSql(sql) {
return format(sql);
mapHighlightingLanguage(language) {
if (language === 'sql') {
return language;
} else if(language === 'sqlsrv') {
return 'tsql';
}
return 'pgsql';
}
}
}
</script>

<template>
<preview-screen title="Query Details" resource="queries" :id="$route.params.id" v-on:ready="highlightSQL()">
<preview-screen title="Query Details" resource="queries" :id="$route.params.id">
<template slot="table-parameters" slot-scope="slotProps">
<tr>
<td class="table-fit text-muted">Connection</td>
Expand Down Expand Up @@ -58,8 +78,10 @@
</li>
</ul>
<div class="code-bg p-4 mb-0 text-white">
<copy-clipboard :data="formatSql(slotProps.entry.content.sql)">
<pre class="code-bg text-white" ref="sqlcode">{{ formatSql(slotProps.entry.content.sql) }}</pre>
<copy-clipboard :data="formatSql(slotProps.entry.content.sql, slotProps?.entry?.content?.driver ?? 'sql')">
<higlighter :code="formatSql(slotProps.entry.content.sql, slotProps.entry.content?.driver ?? 'sql')"
:language="mapHighlightingLanguage(slotProps.entry.content?.driver ?? 'sql')"
class="code-bg text-white class" />
</copy-clipboard>
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/Watchers/QueryWatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function recordQuery(QueryExecuted $event)
'file' => $caller['file'],
'line' => $caller['line'],
'hash' => $this->familyHash($event),
'driver' => $event->connection->getDriverName(),
])->tags($this->tags($event)));
}
}
Expand Down Expand Up @@ -90,6 +91,10 @@ protected function formatBindings($event)
*/
public function replaceBindings($event)
{
if (version_compare(app()->version(), '10.0.0', '>=')) {
return $event->connection->getQueryGrammar()->substituteBindingsIntoRawSql($event->sql, $event->bindings);
}

$sql = $event->sql;

foreach ($this->formatBindings($event) as $key => $binding) {
Expand Down
Loading

0 comments on commit 1394592

Please sign in to comment.