From 53b2d8372ff111c37824a2fb6836d99721771671 Mon Sep 17 00:00:00 2001 From: twoxfh <30451770+twoxfh@users.noreply.github.com> Date: Wed, 18 Aug 2021 14:22:30 -0400 Subject: [PATCH] Updating how database object information is getting retrieved (#79) * Updating how database object information is getting retrieved I updated the SQLite query for gathering database objects to make use of the JSON1 extension so you can grab tables and views name, their associated columns with types and set it to the schema. This removes the need to work with DDL's. Hints for Tables and Views works since my approach is they are both database objects. --- src/lib/database/_statements.js | 46 ------------------- src/lib/database/index.js | 23 +++------- tests/lib/database/_statements.spec.js | 28 ----------- tests/lib/database/database.spec.js | 6 +-- .../Main/Workspace/Schema/Schema.spec.js | 4 +- 5 files changed, 11 insertions(+), 96 deletions(-) diff --git a/src/lib/database/_statements.js b/src/lib/database/_statements.js index eb0652c..3a89b62 100644 --- a/src/lib/database/_statements.js +++ b/src/lib/database/_statements.js @@ -1,5 +1,3 @@ -import sqliteParser from 'sqlite-parser' - export default { * generateChunks (data, size) { const matrix = Object.keys(data).map(col => data[col]) @@ -47,49 +45,5 @@ export default { result = result.replace(/,\s$/, ');') return result - }, - - 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=.+?"/, '$1') - .replace(/(tokenize=[^,]+)"remove_diacritics=.+?"/, '$1') - .replace(/(tokenize=[^,]+)"separators=.+?"/, '$1') - .replace(/tokenize=.+?(,|\))/, 'tokenize=unicode61$1') - - return sqliteParser(fixedSql) - }, - - /* - * Return an array of columns with name and type. E.g.: - * [ - * { name: 'id', type: 'INTEGER' }, - * { name: 'title', type: 'NVARCHAR(30)' }, - * ] - */ - getColumns (sql) { - const columns = [] - const ast = this.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 } } diff --git a/src/lib/database/index.js b/src/lib/database/index.js index 1f1dca3..92264d6 100644 --- a/src/lib/database/index.js +++ b/src/lib/database/index.js @@ -1,4 +1,3 @@ -import stms from './_statements' import fu from '@/lib/utils/fileIo' // We can import workers like so because of worker-loader: // https://webpack.js.org/loaders/worker-loader/ @@ -81,24 +80,14 @@ class Database { async refreshSchema () { const getSchemaSql = ` - SELECT name, sql - FROM sqlite_master - WHERE type='table' AND name NOT LIKE 'sqlite_%'; + WITH columns as (SELECT a.tbl_name, json_group_array(json_object('name', b.name,'type', IIF(b.type = '', 'N/A', b.type))) as column_json + FROM sqlite_master a, pragma_table_info(a.name) b + WHERE a.type in ('table','view') AND a.name NOT LIKE 'sqlite_%' group by tbl_name + ) + SELECT json_group_array(json_object('name',tbl_name, 'columns', json(column_json))) objects from columns; ` const result = await this.execute(getSchemaSql) - // Parse DDL statements to get column names and types - const parsedSchema = [] - if (result && result.values && result.values.name) { - result.values.name.forEach((table, index) => { - parsedSchema.push({ - name: table, - columns: stms.getColumns(result.values.sql[index]) - }) - }) - } - - // Refresh schema - this.schema = parsedSchema + this.schema = JSON.parse(result.values.objects[0]) } async execute (commands) { diff --git a/tests/lib/database/_statements.spec.js b/tests/lib/database/_statements.spec.js index 1d44633..d0c1a55 100644 --- a/tests/lib/database/_statements.spec.js +++ b/tests/lib/database/_statements.spec.js @@ -35,32 +35,4 @@ describe('_statements.js', () => { 'CREATE table "foo"("id" REAL, "name" TEXT, "isAdmin" INTEGER, "startDate" TEXT);' ) }) - - it('getColumns', () => { - const sql = `CREATE TABLE test ( - col1, - col2 integer, - col3 decimal(5,2), - col4 varchar(30) - )` - expect(stmts.getColumns(sql)).to.eql([ - { name: 'col1', type: 'N/A' }, - { name: 'col2', type: 'integer' }, - { name: 'col3', type: 'decimal(5, 2)' }, - { name: 'col4', type: 'varchar(30)' } - ]) - }) - - it('getColumns with virtual table', async () => { - const sql = ` - CREATE VIRTUAL TABLE test_virtual USING fts4( - col1, col2, - notindexed=col1, notindexed=col2, - tokenize=unicode61 "tokenchars=.+#") - ` - expect(stmts.getColumns(sql)).to.eql([ - { name: 'col1', type: 'N/A' }, - { name: 'col2', type: 'N/A' } - ]) - }) }) diff --git a/tests/lib/database/database.spec.js b/tests/lib/database/database.spec.js index 082beab..0a13a1d 100644 --- a/tests/lib/database/database.spec.js +++ b/tests/lib/database/database.spec.js @@ -133,9 +133,9 @@ describe('database.js', () => { expect(db.schema).to.have.lengthOf(1) expect(db.schema[0].name).to.equal('foo') expect(db.schema[0].columns).to.have.lengthOf(3) - expect(db.schema[0].columns[0]).to.eql({ name: 'id', type: 'real' }) - expect(db.schema[0].columns[1]).to.eql({ name: 'name', type: 'text' }) - expect(db.schema[0].columns[2]).to.eql({ name: 'faculty', type: 'text' }) + expect(db.schema[0].columns[0]).to.eql({ name: 'id', type: 'REAL' }) + expect(db.schema[0].columns[1]).to.eql({ name: 'name', type: 'TEXT' }) + expect(db.schema[0].columns[2]).to.eql({ name: 'faculty', type: 'TEXT' }) const result = await db.execute('SELECT * from foo') expect(result).to.eql(data) diff --git a/tests/views/Main/Workspace/Schema/Schema.spec.js b/tests/views/Main/Workspace/Schema/Schema.spec.js index 1d20de5..d0680dc 100644 --- a/tests/views/Main/Workspace/Schema/Schema.spec.js +++ b/tests/views/Main/Workspace/Schema/Schema.spec.js @@ -166,8 +166,8 @@ describe('Schema.vue', () => { await state.db.refreshSchema.returnValues[0] expect(wrapper.vm.$store.state.db.schema).to.eql([ - { name: 'test', columns: [{ name: 'col1', type: 'real' }, { name: 'col2', type: 'text' }] }, - { name: 'foo', columns: [{ name: 'id', type: 'N/A' }] } + { name: 'foo', columns: [{ name: 'id', type: 'N/A' }] }, + { name: 'test', columns: [{ name: 'col1', type: 'REAL' }, { name: 'col2', type: 'TEXT' }] } ]) const res = await wrapper.vm.$store.state.db.execute('select * from test')