需求来源:在前端需要直接操作本地数据bd文件,通过sql语句来查询数据的,本文是通过sql.js和upload组件来实现的,在上传之后解析db文件,同时支持sql语句查询。
sql源码地址:github.com/sql-js/sql.…
实现方式:1.首先需要下载sql的依赖
npm install sql.js
2.因为目前需求是针对本地上传db文件的,所以只需要部分功能
在node_modules中找到sql.js,将这几个文件拷贝出来。
同时参照sql.js中example里面的gui.js文件写法。
github.com/sql-js/sql.…
我们对其中的功能进行改造,
将需要的文件放在一起,因为解析db文件的时间不确定,所以我们要通过异步的方式来读取db文件,在原文gui.js中是采用了webWorker的方式实现的。参照原文,我们也同样采用webworker形式来实现。
const worker = new Worker('./worker.sql-wasm.js')
首先创建一个新线程,接着开始写我们的方法getDBfile,入参为传入的db文件file,以及commands指令
function getDBfile (file, commands) {}
接着需要创建一个fileReader()
const r = new FileReader()
r.readAsArrayBuffer(file)
然后以readAsArrayBuffer方式解析file文件,然后在FileReader的回调中处理文件,这里是调用的sql.js中的API
try {
worker.postMessage({
action: 'open',
buffer: r.result
}, [r.result])
} catch (exception) {
worker.postMessage({
action: 'open',
buffer: r.result
})
}
将FileReader中的内容以postMessage的方式传入webworker中。
worker.onmessage = function () {
execEditorContents(commands)
}
然后在onmessage中接收,
// Execute the commands when the button is clicked
function execEditorContents (commands) {
return execute(commands)
}
// Run a command in the database
function execute (commands) {
worker.onmessage = function (event) {
const getData = JSON.parse(JSON.stringify(event.data))
getFile(getData)
}
worker.postMessage({
action: 'exec',
sql: commands
})
}
function getFile (fileobj) {
recieveFile = fileobj
}
我们在js文件中提前定义了recieveFile来接收返回的字符串
3.在vue项目中,因为笔者项目中采用的是element.js,所以以el-upload为例子
<el-upload
id="dbFile"
ref="uploadFile"
:accept="fileType"
:action="uploadFile"
:before-upload="uploadChange"
class="upload-demo"
drag
multiple>
import { execEditorContents, getDBfile, recieveFile } from '@/untils/sql/GUI'
在before-upload中拦截file文件,发送给getDBfile
uploadChange (file) {
const sql = "SELECT name from sqlite_master where type = 'table'"
getDBfile(file, sql)
}
文件已经传输过去,因为不同线程,所以我们用setTimeout来接收返回数据
setTimeout(() => {
this.Getoption = recieveFile
}, 500)
这样就可以拿到解析完成的db文件里面的数据了,同时支持sql语句查询,在execEditorContents中输入Sql语句再用setTimeout接收recieveFile的值即可。 附上源码gui.js
// Start the worker in which sql.js will run
const worker = new Worker('./worker.sql-wasm.js')
let recieveFile = {}
// Open a database
worker.postMessage({ action: 'open' })
// Run a command in the database
function execEditorContents (commands) {
return new Promise((resolve, reject) => {
worker.onmessage = function (event) {
const getData = JSON.parse(JSON.stringify(event.data))
console.log('getDatagetData', getData)
resolve(getData)
getFile(getData)
}
worker.postMessage({
action: 'exec',
sql: commands
})
})
}
// worker.addEventListener('message', function (evt) {
// if (evt.data.results) {
// recieveFile = evt.data.results[0].values
// }
// })
function getFile (fileobj) {
recieveFile = fileobj
}
function getDBfile (file, commands) {
return new Promise((resolve, reject) => {
const r = new FileReader()
r.onload = function () {
worker.onmessage = function () {
execEditorContents(commands).then((res) => {
resolve(res)
})
}
try {
worker.postMessage({
action: 'open',
buffer: r.result
}, [r.result])
} catch (exception) {
worker.postMessage({
action: 'open',
buffer: r.result
})
}
}
r.readAsArrayBuffer(file)
})
}
export {
getDBfile,
execEditorContents,
recieveFile
}
因为不知道什么时候能够解析完成db文件,所以我们采用promise的方式来接收数据
需要的注意的是,vue项目在编译的时候,会把worker.wasm.js识别成为html文件,所以需要在webpack中添加识别wasm文件的功能。
config.module.rule('wasm').test(/.wasm$/).type('javascript/auto')