1
0
mirror of https://github.com/lana-k/sqliteviz.git synced 2025-12-06 18:18:53 +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"> <div v-if="schemaVisible" class="schema">
<table-description <table-description
v-for="table in schema" v-for="table in schema"
:key="table[0]" :key="table.name"
:name="table[0]" :name="table.name"
:sql="table[1]" :columns="table.columns"
/> />
</div> </div>
</div> </div>

View File

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

View File

@@ -27,51 +27,14 @@
</template> </template>
<script> <script>
import sqliteParser from 'sqlite-parser'
export default { export default {
name: 'TableDescription', name: 'TableDescription',
props: ['name', 'sql'], props: ['name', 'columns'],
data () { data () {
return { return {
colVisible: false 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> </script>

View File

@@ -1,8 +1,46 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import sqliteParser from 'sqlite-parser'
Vue.use(Vuex) 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({ export default new Vuex.Store({
state: { state: {
schema: null, schema: null,
@@ -16,7 +54,14 @@ export default new Vuex.Store({
}, },
mutations: { mutations: {
saveSchema (state, schema) { 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) { saveDbFile (state, file) {
state.dbFile = file state.dbFile = file