ES6(六)用Class + Promise封装一下Web SQL

Web SQL

首先呢,HTML5已经放弃了 Web SQL,这里做这个封装,主要是为了练手,另外是为了做在线演示。

后端一般都采用关系型数据库,有些关于sql语句的在线演示就需要弄个后端,但是成本比较高,那么如果能够用前端的websql模仿一下,是不是就省钱了呢?

因为都是用sql语句,基础的操作方式还是相同的,介绍一下原理是没啥问题的,所以呢,并不是真的要在项目里面使用,目前初步的感受来说,挺麻烦的。。。

打开数据库

要说webSQL还真是简单,或者说是简陋,就是开库,事务,提交SQL语句,然后就没了,自由发挥吧。

那么还是简单的封装一下。

/**
 * webSQL 的封装,基于 promise 便于操作
 * * 建立数据库
 * * 封装sql实现增删改查
 */
export default class webSQLHelp {
  constructor (dbName, ver, description) { // constructor是一个构造方法,用来接收参数
    this.dbName = dbName // this代表的是实例对象
    this.ver = ver
    this.description = description
    this.db = window.openDatabase(this.dbName, this.ver, this.description, 2 * 1024 * 1024)
  }

  /**
   * 打开指定的webSQL数据库
   * @returns 数据库的实例
   */
  openDb () {
    return this.db
  }
  ...
}

先体验一下ES6 的 class(不是TS的),果然和 function 没啥大的区别,初始化传入参数打开数据库,备用。
好像把数据库名称记录下来似乎也没啥大用。

建立表

然后用建表语句建立表,看了一下资料,似乎也不用设置字段的类型,那么就简单一点,根据对象的属性来建立一个表。

  /**
   * 创建表
   * @param { string } tableName 表名
   * @param { object } columns 表的对象,比如{name:'jyk', age: 12}
   * @returns 成功或者失败
   */
  createTable (tableName, columns) {
    const promise = new Promise((resolve, reject) => {
      console.log('this.db', this.db)
      // 记录字段名称,不设置类型了。
      const cols = []
      for (const key in columns) {
        cols.push(key)
      }
      const sql = `CREATE TABLE IF NOT EXISTS ${tableName}
        (ID INTEGER PRIMARY KEY ASC, ${cols.join(',')} )`
      console.log('createSQL:', sql)
      // 调用事务,建立表
      this.db.transaction((tx) => {
        tx.executeSql(sql, [], (tx, results) => {
          console.log(tx, results)
          resolve(results)
        }, (tx, err) => {
          console.log(tx, err)
          reject(err)
        })
      })
    })

    return promise
  }

用 Promise 代替回调的方式。传入表名和对象,然后创建建表的SQL,提交建表搞定。

这里想实现 那种 表名.insert()的形式,但是水平有限,没弄出来。

添加数据

  /**
   * 插入数据
   * @param { string } tableName 表名
   * @param { object } object 保存的对象
   * @returns 新增的ID值
   */
  insert (tableName, object) {
    const promise = new Promise((resolve, reject) => {
      console.log('this.db', this.db)
      // 记录字段名称
      const colNames = []
      // 记录字段对应的值
      const colValues = []
      // 记录字段对应的占位符合
      const cols = []
      // 变量对象,记录 key和 value
      for (const key in object) {
        colNames.push(key)
        // colValues.push('"' + object[key] + '"')
        colValues.push(object[key])
        cols.push('?')
      }
      const sql = `INSERT INTO ${tableName}
        ( ${colNames.join(',')} ) VALUES ( ${cols.join(',')} )`

      console.log('insertSQL:', sql)
      this.db.transaction((tx) => {
        tx.executeSql(sql, colValues, (tx, results) => {
          console.log(tx, results)
          // 成功了,返回给调用者
          resolve(results.insertId)
        }, (tx, err) => {
          console.log(tx, err)
          reject(err)
        })
      })
    })

    return promise
  }

还是传入表名和对象,然后生成 insert 的SQL语句,提交添加搞定。

修改数据

  /**
   * 修改数据
   * @param { String } tableName 表名
   * @param { Object } object 要修改的对象值
   * @param { Number } idValue 修改依据,id 的值
   * @returns 修改影响的行数
   */
  update (tableName, object, idValue) {
    const promise = new Promise((resolve, reject) => {
      console.log('this.db', this.db)
      // 记录字段名称
      const colNames = []
      // 记录字段对应的值
      const colValues = []
      // 变量对象,记录 key和 value
      for (const key in object) {
        colNames.push(key + '=? ')
        colValues.push(object[key])
      }
      // 加入查询条件
      colValues.push(idValue)

      const sql = `UPDATE ${tableName} SET ${colNames.join(',')} WHERE id=?`

      console.log('updateSQL:', sql)
      console.log('updateSQL2:', colValues)
      this.db.transaction((tx) => {
        tx.executeSql(sql, colValues, (tx, results) => {
          console.log(tx, results)
          // 成功了,返回给调用者 影响行数
          resolve(results.rowsAffected)
        }, (tx, err) => {
          console.log(tx, err)
          reject(err)
        })
      })
    })

    return promise
  }

一样,改改SQL就好。另外需要加一个where 的条件,否则就都删掉了。

删除数据

  /**
   * 删除一条记录
   * @param { String } tableName 表名
   * @param { Number } idValue 删除依据
   * @returns 删除状态
   */
  delete (tableName, idValue) {
    const promise = new Promise((resolve, reject) => {
      console.log('this.db', this.db)
      const sql = `DELETE FROM ${tableName} WHERE id=?`
      console.log('deleteSQL:', sql)
      this.db.transaction((tx) => {
        tx.executeSql(sql, [idValue], (tx, results) => {
          console.log(tx, results)
          // 成功了,返回给调用者 影响行数
          resolve(results.rowsAffected)
        }, (tx, err) => {
          console.log(tx, err)
          reject(err)
        })
      })
    })

    return promise
  }

这个最简单了,delete一下就好。

查询数据

  /**
   * 查询数据
   * @param { string } tableName 要查询的表名
   * @param { object } showCols 显示字段
   * @param { object } query 查询条件
   * @returns 查询结果,数组形式
   */
  select (tableName, showCols, query) {
    this.findKind = {
      // 字符串
      401: ' {col} = ? ',
      402: ' {col} <> ? ',
      403: ' {col} like ? ',
      404: ' {col} not like ? ',
      405: ' {col} like ? ', // 起始于
      406: ' {col} like ? ', // 结束于
      // 数字
      411: ' {col} = ? ',
      412: ' {col} <> ? ',
      413: ' {col} > ? ',
      414: ' {col} >= ? ',
      415: ' {col} < ? ',
      416: ' {col} <= ? ',
      417: ' {col} between ? and ? ',
      // 日期
      421: ' {col} = ? ',
      422: ' {col} <> ? ',
      423: ' {col} > ? ',
      424: ' {col} >= ? ',
      425: ' {col} < ? ',
      426: ' {col} <= ? ',
      427: ' {col} between ? and ? ',
      // 范围
      441: ' {col} in (?)'
    }
    const promise = new Promise((resolve, reject) => {
      const _whereCol = []
      const _whereValue = []
      for (const key in query) {
        const val = query[key]
        _whereCol.push(this.findKind[val[0]].replace('{col}', key))
        switch (val[0]) {
          case 403: // like
          case 404: // not like
            _whereValue.push('%' + val[1] + '%')
            break
          case 405: // like a%
            _whereValue.push(val[1] + '%')
            break
          case 406: // like %a
            _whereValue.push('%' + val[1])
            break
          case 417: // between 数字
          case 427: // between 日期
            _whereValue.push(...val[1])
            break
          case 441: // in
            _whereCol[_whereCol.length - 1] =
              _whereCol[_whereCol.length - 1]
                .replace('?', val[1].map(a => '?').join(','))
            _whereValue.push(...val[1])
            break
          default:
            _whereValue.push(val[1])
            break
        }
      }
      if (_whereCol.length === 0) {
        _whereCol.push(' 1=1 ')
      }
      const sql = `SELECT * FROM ${tableName} WHERE ${_whereCol.join(' and ')}`
      console.log('selectSQL1:', sql)
      console.log('selectSQL2:', _whereValue)
      this.db.transaction((tx) => {
        tx.executeSql(sql, _whereValue, (tx, results) => {
          console.log(tx, results)
          // 成功了,返回给调用者 影响行数
          resolve(results.rows)
        }, (tx, err) => {
          console.log(tx, err)
          reject(err)
        })
      })
    })

    return promise
  }

好吧,其实主要就是为了这个查询,这不在做查询控件么,演示的时候,还是有个数据变化更生动一些,但是有没钱弄后端服务器。于是就用websql代替一下吧。

这里设置了一个查询结构,这个 select 就是把这个查询结构解析成SQL语句,然后交给数据库执行,看看查询效果。

使用方法

在vue环境下使用

import WebSqlHelp from '@/store-nf/websql-help.js'

export default {
  name: 'websql',
  components: {
  },
  setup (props, ctx) {
    const help = new WebSqlHelp('db-findtest', '1.0', '演示一下查询控件')
    console.log(help)
    const person = {
      name: 'jyk',
      age: 18,
      brithday: '1970-1-1',
      aa: {
        a1: 'a111',
        a2: 'a222'
      }
    }

    const sqlCreate = () => {
      // 依据 person 建立一个表
      help.createTable('person3', person).then(() => {
        // 往表里面加数据
        help.insert('person3', person).then((id) => {
          console.log('newId', id)
        })
      })
    }

    const zsgc = () => {
      // 修改指定的数据
      person.age = 111
      help.update('person3', person, 3).then((id) => {
        console.log('updateId', id)
      })
      // 删除指定的数据
      help.delete('person3', 4).then((id) => {
        console.log('deleteId', id)
      })
    }

    const dataList = reactive([])
    const sqlSelect = () => {
      // 查询数据
      help.select('person3', {}, {
        // id: [401, 2]
      }).then((data) => {
        console.log('select:', data)
        dataList.length = 0
        dataList.push(...data)
      })
    }

    return {
      sqlCreate,
      sqlSelect,
      dataList
    }
  }
}

  • 嵌套对象
    默认只支持单层属性,套娃是不支持的,直接存 “[object Object]”这个东东进去。
    只是简单的演示,就不做转换了。

  • 多表关联
    没考虑那么复杂,因为没打算演示这些复杂的操作,头疼。就简单粗暴的演示一下单表查询就好。
    同理,分组统计这类的也不考虑。

总结

发现好多小问题,前端嘛,还是用indexedDB的好,用webSQL实在太不放心了,维护起来也感觉忒麻烦。

对了,还得写个删除表和库的函数,F12也没有个删除的功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容