mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-07 02:28:54 +08:00
CSV import as a table and db connection rework
- Add csv to existing db #32 - [RFE] Simplify working with temporary tables #53
This commit is contained in:
@@ -4,6 +4,9 @@ import { mount, createLocalVue } from '@vue/test-utils'
|
||||
import Vuex from 'vuex'
|
||||
import Schema from '@/views/Main/Editor/Schema'
|
||||
import TableDescription from '@/views/Main/Editor/Schema/TableDescription'
|
||||
import database from '@/lib/database'
|
||||
import fIo from '@/lib/utils/fileIo'
|
||||
import csv from '@/components/CsvImport/csv'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
@@ -16,7 +19,9 @@ describe('Schema.vue', () => {
|
||||
it('Renders DB name on initial', () => {
|
||||
// mock store state
|
||||
const state = {
|
||||
dbName: 'fooDB'
|
||||
db: {
|
||||
dbName: 'fooDB'
|
||||
}
|
||||
}
|
||||
const store = new Vuex.Store({ state })
|
||||
|
||||
@@ -31,7 +36,9 @@ describe('Schema.vue', () => {
|
||||
it('Schema visibility is toggled when click on DB name', async () => {
|
||||
// mock store state
|
||||
const state = {
|
||||
dbName: 'fooDB'
|
||||
db: {
|
||||
dbName: 'fooDB'
|
||||
}
|
||||
}
|
||||
const store = new Vuex.Store({ state })
|
||||
|
||||
@@ -48,30 +55,32 @@ describe('Schema.vue', () => {
|
||||
it('Schema filter', async () => {
|
||||
// mock store state
|
||||
const state = {
|
||||
dbName: 'fooDB',
|
||||
schema: [
|
||||
{
|
||||
name: 'foo',
|
||||
columns: [
|
||||
{ name: 'id', type: 'INTEGER' },
|
||||
{ name: 'title', type: 'NVARCHAR(24)' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'bar',
|
||||
columns: [
|
||||
{ name: 'id', type: 'INTEGER' },
|
||||
{ name: 'price', type: 'INTEGER' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'foobar',
|
||||
columns: [
|
||||
{ name: 'id', type: 'INTEGER' },
|
||||
{ name: 'price', type: 'INTEGER' }
|
||||
]
|
||||
}
|
||||
]
|
||||
db: {
|
||||
dbName: 'fooDB',
|
||||
schema: [
|
||||
{
|
||||
name: 'foo',
|
||||
columns: [
|
||||
{ name: 'id', type: 'INTEGER' },
|
||||
{ name: 'title', type: 'NVARCHAR(24)' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'bar',
|
||||
columns: [
|
||||
{ name: 'id', type: 'INTEGER' },
|
||||
{ name: 'price', type: 'INTEGER' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'foobar',
|
||||
columns: [
|
||||
{ name: 'id', type: 'INTEGER' },
|
||||
{ name: 'price', type: 'INTEGER' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
const store = new Vuex.Store({ state })
|
||||
|
||||
@@ -101,15 +110,69 @@ describe('Schema.vue', () => {
|
||||
|
||||
it('exports db', async () => {
|
||||
const state = {
|
||||
dbName: 'fooDB',
|
||||
db: {
|
||||
dbName: 'fooDB',
|
||||
export: sinon.stub().resolves()
|
||||
}
|
||||
}
|
||||
const store = new Vuex.Store({ state })
|
||||
const wrapper = mount(Schema, { store, localVue })
|
||||
|
||||
await wrapper.findComponent({ name: 'export-icon' }).trigger('click')
|
||||
await wrapper.findComponent({ name: 'export-icon' }).find('svg').trigger('click')
|
||||
expect(state.db.export.calledOnceWith('fooDB'))
|
||||
})
|
||||
|
||||
it('adds table', async () => {
|
||||
const file = { name: 'test.csv' }
|
||||
sinon.stub(fIo, 'getFileFromUser').resolves(file)
|
||||
|
||||
sinon.stub(csv, 'parse').resolves({
|
||||
delimiter: '|',
|
||||
data: {
|
||||
columns: ['col1', 'col2'],
|
||||
values: [
|
||||
[1, 'foo']
|
||||
]
|
||||
},
|
||||
hasErrors: false,
|
||||
messages: []
|
||||
})
|
||||
|
||||
const state = {
|
||||
db: database.getNewDatabase()
|
||||
}
|
||||
state.db.dbName = 'db'
|
||||
state.db.execute('CREATE TABLE foo(id)')
|
||||
state.db.refreshSchema()
|
||||
sinon.spy(state.db, 'refreshSchema')
|
||||
|
||||
const store = new Vuex.Store({ state })
|
||||
const wrapper = mount(Schema, { store, localVue })
|
||||
sinon.spy(wrapper.vm.$refs.addCsv, 'previewCsv')
|
||||
sinon.spy(wrapper.vm, 'addCsv')
|
||||
sinon.spy(wrapper.vm.$refs.addCsv, 'loadFromCsv')
|
||||
|
||||
await wrapper.findComponent({ name: 'add-table-icon' }).find('svg').trigger('click')
|
||||
await wrapper.vm.$refs.addCsv.previewCsv.returnValues[0]
|
||||
await wrapper.vm.addCsv.returnValues[0]
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('[data-modal="addCsv"]').exists()).to.equal(true)
|
||||
await wrapper.find('#csv-import').trigger('click')
|
||||
await wrapper.vm.$refs.addCsv.loadFromCsv.returnValues[0]
|
||||
await wrapper.find('#csv-finish').trigger('click')
|
||||
expect(wrapper.find('[data-modal="addCsv"]').exists()).to.equal(false)
|
||||
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' }] }
|
||||
])
|
||||
|
||||
const res = await wrapper.vm.$store.state.db.execute('select * from test')
|
||||
expect(res).to.eql({
|
||||
columns: ['col1', 'col2'],
|
||||
values: [[1, 'foo']]
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,6 +7,5 @@ describe('SqlEditor.vue', () => {
|
||||
const wrapper = mount(SqlEditor)
|
||||
await wrapper.findComponent({ name: 'codemirror' }).vm.$emit('input', 'SELECT * FROM foo')
|
||||
expect(wrapper.emitted('input')[0]).to.eql(['SELECT * FROM foo'])
|
||||
// Take a pause to keep proper state in debounced '@/views/Main/Editor/Tabs/Tab/SqlEditor/hint'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,22 +11,24 @@ describe('hint.js', () => {
|
||||
|
||||
it('Calculates table list for hint', () => {
|
||||
// mock store state
|
||||
const schema = [
|
||||
{
|
||||
name: 'foo',
|
||||
columns: [
|
||||
{ name: 'fooId', type: 'INTEGER' },
|
||||
{ name: 'name', type: 'NVARCHAR(20)' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'bar',
|
||||
columns: [
|
||||
{ name: 'barId', type: 'INTEGER' }
|
||||
]
|
||||
}
|
||||
]
|
||||
sinon.stub(state, 'schema').value(schema)
|
||||
const db = {
|
||||
schema: [
|
||||
{
|
||||
name: 'foo',
|
||||
columns: [
|
||||
{ name: 'fooId', type: 'INTEGER' },
|
||||
{ name: 'name', type: 'NVARCHAR(20)' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'bar',
|
||||
columns: [
|
||||
{ name: 'barId', type: 'INTEGER' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
sinon.stub(state, 'db').value(db)
|
||||
|
||||
// mock showHint and editor
|
||||
sinon.stub(CM, 'showHint')
|
||||
@@ -52,16 +54,18 @@ describe('hint.js', () => {
|
||||
|
||||
it('Add default table if there is only one table in schema', () => {
|
||||
// mock store state
|
||||
const schema = [
|
||||
{
|
||||
name: 'foo',
|
||||
columns: [
|
||||
{ name: 'fooId', type: 'INTEGER' },
|
||||
{ name: 'name', type: 'NVARCHAR(20)' }
|
||||
]
|
||||
}
|
||||
]
|
||||
sinon.stub(state, 'schema').value(schema)
|
||||
const db = {
|
||||
schema: [
|
||||
{
|
||||
name: 'foo',
|
||||
columns: [
|
||||
{ name: 'fooId', type: 'INTEGER' },
|
||||
{ name: 'name', type: 'NVARCHAR(20)' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
sinon.stub(state, 'db').value(db)
|
||||
|
||||
// mock showHint and editor
|
||||
sinon.stub(CM, 'showHint')
|
||||
@@ -190,7 +194,7 @@ describe('hint.js', () => {
|
||||
|
||||
it('tables is empty object when schema is null', () => {
|
||||
// mock store state
|
||||
sinon.stub(state, 'schema').value(null)
|
||||
sinon.stub(state, 'db').value({ schema: null })
|
||||
|
||||
// mock showHint and editor
|
||||
sinon.stub(CM, 'showHint')
|
||||
|
||||
@@ -182,7 +182,8 @@ describe('Tab.vue', () => {
|
||||
const state = {
|
||||
currentTabId: 1,
|
||||
db: {
|
||||
execute: sinon.stub().rejects(new Error('There is no table foo'))
|
||||
execute: sinon.stub().rejects(new Error('There is no table foo')),
|
||||
refreshSchema: sinon.stub().resolves()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ describe('Tab.vue', () => {
|
||||
currentTabId: 1,
|
||||
db: {
|
||||
execute: sinon.stub().resolves(result),
|
||||
getSchema: sinon.stub().resolves({ dbName: '', schema: [] })
|
||||
refreshSchema: sinon.stub().resolves()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,36 +254,17 @@ describe('Tab.vue', () => {
|
||||
columns: ['id', 'name'],
|
||||
values: []
|
||||
}
|
||||
const newSchema = {
|
||||
dbName: 'fooDb',
|
||||
schema: [
|
||||
{
|
||||
name: 'foo',
|
||||
columns: [
|
||||
{ name: 'id', type: 'INTEGER' },
|
||||
{ name: 'title', type: 'NVARCHAR(30)' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'bar',
|
||||
columns: [
|
||||
{ name: 'a', type: 'N/A' },
|
||||
{ name: 'b', type: 'N/A' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// mock store state
|
||||
const state = {
|
||||
currentTabId: 1,
|
||||
dbName: 'fooDb',
|
||||
db: {
|
||||
execute: sinon.stub().resolves(result),
|
||||
getSchema: sinon.stub().resolves(newSchema)
|
||||
refreshSchema: sinon.stub().resolves()
|
||||
}
|
||||
}
|
||||
|
||||
sinon.spy(mutations, 'saveSchema')
|
||||
const store = new Vuex.Store({ state, mutations })
|
||||
|
||||
// mount the component
|
||||
@@ -300,7 +282,6 @@ describe('Tab.vue', () => {
|
||||
})
|
||||
|
||||
await wrapper.vm.execute()
|
||||
expect(state.db.getSchema.calledOnceWith('fooDb')).to.equal(true)
|
||||
expect(mutations.saveSchema.calledOnceWith(state, newSchema)).to.equal(true)
|
||||
expect(state.db.refreshSchema.calledOnce).to.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user