1
0
mirror of https://github.com/lana-k/sqliteviz.git synced 2025-12-06 10:08:52 +08:00

Add schema tokens in codemirror autocomplit #1

This commit is contained in:
lana-k
2020-11-12 15:30:37 +01:00
parent c5fa3e903a
commit f65953a2e1
4 changed files with 65 additions and 46 deletions

View File

@@ -31,9 +31,9 @@
<div v-if="schemaVisible" class="schema">
<table-description
v-for="table in schema"
:key="table[0]"
:name="table[0]"
:sql="table[1]"
:key="table.name"
:name="table.name"
:columns="table.columns"
/>
</div>
</div>

View File

@@ -17,11 +17,11 @@ import { debounce } from 'debounce'
const sqlHint = CM.hint.sql
CM.hint.sql = (cm, options) => {
const token = cm.getTokenAt(cm.getCursor()).string
const token = cm.getTokenAt(cm.getCursor()).string.toUpperCase()
const result = sqlHint(cm, options)
// Don't show the hint if there is only one option
// and the token is already completed with this option
if (result.list.length === 1 && result.list[0].text === token) {
if (result.list.length === 1 && result.list[0].text.toUpperCase() === token) {
result.list = []
}
return result
@@ -46,13 +46,24 @@ export default {
}
}
},
computed: {
tables () {
const tables = {}
if (this.$store.state.schema) {
this.$store.state.schema.forEach(table => {
tables[table.name] = table.columns.map(column => column.name)
})
}
return tables
}
},
watch: {
query () {
this.$emit('input', this.query)
}
},
methods: {
onCmChange: debounce((editor) => {
onCmChange: debounce(function (editor) {
// Don't show autocomplete after a space or semicolon or in string literals
const ch = editor.getTokenAt(editor.getCursor()).string.slice(-1)
const tokenType = editor.getTokenAt(editor.getCursor()).type
@@ -61,7 +72,7 @@ export default {
}
const hintOptions = {
// tables: {table: [col1, col2], table2: [colA, colB]},
tables: this.tables,
completeSingle: false,
completeOnSingleClick: true,
alignWithWord: false

View File

@@ -27,51 +27,14 @@
</template>
<script>
import sqliteParser from 'sqlite-parser'
export default {
name: 'TableDescription',
props: ['name', 'sql'],
props: ['name', 'columns'],
data () {
return {
colVisible: false
}
},
computed: {
ast () {
// There is a bug is sqlite-parser
// It throws an error if tokenizer has an arguments:
// https://github.com/codeschool/sqlite-parser/issues/59
const fixedSql = this.sql
.replace(/(?<=tokenize=.+)"tokenchars=.+"/, '')
.replace(/(?<=tokenize=.+)"remove_diacritics=.+"/, '')
.replace(/(?<=tokenize=.+)"separators=.+"/, '')
.replace(/tokenize=.+(?=(,|\)))/, 'tokenize=unicode61')
return sqliteParser(fixedSql)
},
columns () {
const columns = []
const columnDefinition = this.ast.statement[0].format === 'table'
? this.ast.statement[0].definition
: this.ast.statement[0].result.args.expression // virtual table
columnDefinition.forEach(item => {
if (item.variant === 'column' && ['identifier', 'definition'].includes(item.type)) {
let type = item.datatype ? item.datatype.variant : 'N/A'
if (item.datatype && item.datatype.args) {
type = type + '(' + item.datatype.args.expression[0].value
if (item.datatype.args.expression.length === 2) {
type = type + ', ' + item.datatype.args.expression[1].value
}
type = type + ')'
}
columns.push({ name: item.name, type: type })
}
})
return columns
}
}
}
</script>

View File

@@ -1,8 +1,46 @@
import Vue from 'vue'
import Vuex from 'vuex'
import sqliteParser from 'sqlite-parser'
Vue.use(Vuex)
function getAst (sql) {
// There is a bug is sqlite-parser
// It throws an error if tokenizer has an arguments:
// https://github.com/codeschool/sqlite-parser/issues/59
const fixedSql = sql
.replace(/(?<=tokenize=.+)"tokenchars=.+"/, '')
.replace(/(?<=tokenize=.+)"remove_diacritics=.+"/, '')
.replace(/(?<=tokenize=.+)"separators=.+"/, '')
.replace(/tokenize=.+(?=(,|\)))/, 'tokenize=unicode61')
return sqliteParser(fixedSql)
}
function getColumns (sql) {
const columns = []
const ast = getAst(sql)
const columnDefinition = ast.statement[0].format === 'table'
? ast.statement[0].definition
: ast.statement[0].result.args.expression // virtual table
columnDefinition.forEach(item => {
if (item.variant === 'column' && ['identifier', 'definition'].includes(item.type)) {
let type = item.datatype ? item.datatype.variant : 'N/A'
if (item.datatype && item.datatype.args) {
type = type + '(' + item.datatype.args.expression[0].value
if (item.datatype.args.expression.length === 2) {
type = type + ', ' + item.datatype.args.expression[1].value
}
type = type + ')'
}
columns.push({ name: item.name, type: type })
}
})
return columns
}
export default new Vuex.Store({
state: {
schema: null,
@@ -16,7 +54,14 @@ export default new Vuex.Store({
},
mutations: {
saveSchema (state, schema) {
state.schema = schema
const parsedSchema = []
schema.forEach(item => {
parsedSchema.push({
name: item[0],
columns: getColumns(item[1])
})
})
state.schema = parsedSchema
},
saveDbFile (state, file) {
state.dbFile = file