如何在vue项目使用sql.js来解析db文件

974 阅读2分钟

需求来源:在前端需要直接操作本地数据bd文件,通过sql语句来查询数据的,本文是通过sql.js和upload组件来实现的,在上传之后解析db文件,同时支持sql语句查询。

sql源码地址:github.com/sql-js/sql.…

实现方式:1.首先需要下载sql的依赖
npm install sql.js
2.因为目前需求是针对本地上传db文件的,所以只需要部分功能 image.png
在node_modules中找到sql.js,将这几个文件拷贝出来。
同时参照sql.js中example里面的gui.js文件写法。
github.com/sql-js/sql.…
我们对其中的功能进行改造,
image.png
将需要的文件放在一起,因为解析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')

参考文档:github.com/sql-js/sql.…