JsStore是IndexedDB的包装器。它提供了简单的SQL像api,这是容易学习和使用的。
IndexedDb查询可以在web worker内部执行,JsStore通过提供一个单独的worker文件来保持这种功能。
因此查询可以以两种方式执行——在web worker内部或在web worker之外。建议使用web worker,因为它在后台线程中运行脚本。
在之前几篇我们使用的Indexed是相关函数api,实现某些功能难度较大,但使用JsStore之后就会比较方便了。
这里还是以Vue技术框架为例,带领大家使用JsStore来实现增删改查功能。
一、安装
安装JsStore的方法多种多样,我们可以从github下载脚本,也可以通过npm进行安装。
1.1 安装最新版本
npm install jsstore
1.2 安装指定版本
npm install jsstore@3.0.0
二、创建数据库
2.1 创建连接文件
jsstore -它包含所有的api和你的代码与它的交互,jsstore worker 它包含了所有的逻辑,可以用来创建有worker或没有worker的连接。
在src目录下创建src/db/index.js文件,来实例connection连接对象,代码如下:
import { Connection } from "jsstore";
import workerInjector from "jsstore/dist/worker_injector";
let connection = new Connection();
connection.addPlugin(workerInjector);
export default connection;
2.2 列表参数
jsstore中的Column是一个对象,其中列名是键,列选项是值。
列的选项:
名称 | 类型 | 描述 |
---|---|---|
primaryKey | boolean | 将此列声明为主键(可选) |
notNull | boolean | 确保该列值不应为空(可选) |
dataType | JsStore.DATA_TYPE | 此列的数据类型(可选) |
autoIncrement | boolean | 自动增加值(可选) |
unique | boolean | 该列将具有惟一值(可选) |
default | any | 在未指定列时为列提供默认值(可选) |
multiEntry | boolean | 提供对数组值内部搜索的支持(可选) |
enableSearch | boolean | 打开/关闭该列的搜索(可选) |
keyPath | string[] | 允许你使用多个索引//可选 |
2.3 数据类型
数据类型DATA_TYPE是公共的,所以可以使用它来定义字段的类型。
类型名称 | 对应类型 | 描述 |
---|---|---|
String | string | 字符串 |
Number | number | 数值 |
DateTime | date_time | 值应该是date对象,即value = new date () |
Object | object | 对象 |
Array | array | 数组 |
Boolean | boolean | 布尔值 |
2.4 创建数据表
在src目录下创建src/db/service.js文件,用来定义表结构和数据类型,并定义initJsStore()初始化数据库函数,代码如下:
import connection from './index.js';
import { DATA_TYPE } from "jsstore";
const getDatabase = () => {
//用户表
const UserTable = {
name: "Users",
columns: {
id: { primaryKey: true, autoIncrement: true },
username: { notNull: true, dataType: DATA_TYPE.String },
password: { notNull: true, dataType: DATA_TYPE.String },
role: { notNull: true, dataType: DATA_TYPE.Number },
token: { notNull: false, dataType: DATA_TYPE.String },
createtime: { notNull: true, dataType: DATA_TYPE.DateTime },
updatetime: { notNull: true, dataType: DATA_TYPE.DateTime },
}
}
//岗位管理
const PostTable = {
name: "Post",
columns: {
id: { primaryKey: true, autoIncrement: true },
name: { notNull: true, dataType: DATA_TYPE.String },
remark: { notNull: false, dataType: DATA_TYPE.String },
createtime: { notNull: true, dataType: DATA_TYPE.DateTime },
updatetime: { notNull: true, dataType: DATA_TYPE.DateTime },
}
}
const dataBase = {
name: "test_System",
tables: [UserTable, PostTable],
version: 1
};
return dataBase;
}
export const initJsStore = async () => {
const dataBase = await getDatabase();
return await connection.initDb(dataBase);
}
在service.js创建好后,在App.vue中初始化数据库,代码如下:
<script>
import { mapGetters } from 'vuex'
import { initJsStore } from '@/db/service.js'
export default {
name: 'App',
data(){
return {
users: new UserService()
}
},
created() {
initJsStore();
}
}
</script>
三、封装实体模型
通过定义实体模型,class是构造函数的语法糖,理解如何使用原型对象实现类和类继承。通过类来创建对象,使得开发不必写重复的代码,以达到代码复用的目的。
3.1 构建类
引入connection实例来连接数据库,通过JsStore的api函数实现用户表的增删改查。引入md5实现用户密码的加密处理,md5大家可以从网上下载js文件引入,也可以通过npm进行安装。
import { connection } from "@/db/index.js";
import { hex_md5 } from '@/utils/md5'
export class UserService {
constructor(){
this.tableName = "Users";
}
}
3.2 查询数据
select api用于从数据库中选择数据,相关参数选项如下:
名称 | 类型 | 描述 |
---|---|---|
limit | Number | Limit用于指定要返回的记录数量 |
skip | Number | Skip用于指定要跳过的记录数 |
order | Object | Order By用于根据任何列按升序或降序对数据进行排序。 |
- by | String | 排序列名 |
- type | String | 排序类型- asc/desc,默认为asc |
- idbSorting | Boolean | 是按indexeddb排序还是按jsstore排序,默认- true |
aggregate | Object | 聚合函数对多个值执行计算并返回单个值。 |
- count | Number | 返回指定列的行数。 |
- sum | Number | 返回数值列的总和。 |
- avg | Number | 返回数值列的平均值。 |
- max | Number | 返回指定列的最大值。 |
- min | Number | 返回指定列的最小值。 |
groupBy | String | Group By用于按一个或多个列对结果集进行分组。您还可以将Aggregate函数与group by一起使用,类似于在SQL中使用的方法。 |
distinct | Boolean | Distinct用于返回唯一的结果集。Distinct过滤除主列以外的所有列的结果,因为主列将使结果始终是唯一的。 |
case | Object | Case是选择查询中的一个选项,用于根据某些条件更改存储值。它类似于多个if else语句。因此,一旦条件为真,它就会停止并返回值。 可以使用其他类似于上面使用的'='的运算符符号- '>','>=,'<','<=','!= ' |
join | Object | JsStore支持两种连接——内连接(默认)和左连接。 |
- with | string | 要连接的表的名称 |
- on | string | 连接条件eg - table1。Property = table2.property |
- as | Object | 重命名一些列名,以避免与其他表的列匹配 |
- where | Object | 过滤 |
- order | Object | 对于数据排序——但与没有连接的查询不同,这里的排序略有不同。需要以[tablename]的形式提供查询和表名 |
- groupBy | Object | 进行分组 |
- aggregate | Object | 数据聚合 |
flatten | Boolean | 扁平化是选择查询中的一个选项,它将数组数据扁平化为基本数据。 |
store | Array | Store是select API中的一个选项,允许从变量中查询现有数据。所有查询选项,如排序,在哪里,分组,聚合等都可以执行。 |
如查询用户列表,或指定ID查询用户信息,代码如下:
import connection from "@/db/index.js";
import { hex_md5 } from '@/utils/md5'
export class UserService {
constructor(){
this.tableName = "Users";
}
//获取用户列表信息
getUsers(){
return connection.select({
from: this.tableName
});
}
/**
* 通过ID获取用户信息
* @param {Object} id
*/
getUserById(id){
return connection.select({
from: this.tableName,
where: { id }
});
}
}
获取列表数据,调用getUsers()函数,代码如下:
let users = new UserService();
let data = await users.getUsers();
3.3 条件查询
Where可以用来过滤与Sql Where子句相同的记录,相关参数选项如下:
名称 | 类型 | 描述 |
---|---|---|
like | Object | Like与Where一起使用,用于搜索列中的指定模式。目前我们只支持'%'字符。JsStore支持的一些样例 like “a%”:查找以“a”开头的任何值。 like “%a”:查找以“a”结尾的任何值。 like '%a%':查找在任何位置包含"a"的任何值。 |
in | Array | In允许您在Where查询中指定多个值。它是多重或查询的简写。 |
regex | Regex | Regex与Where一起用于在列值中搜索指定的模式。有关正则表达式的更多信息,请访问mozilla正则表达式指南 |
or | Object | 或可以与where一起使用以过滤记录,以包括任何条件为真的记录。 |
operators | JsStore支持以下操作符:— " > ":查找大于提供值的值。 " < ":查找小于所提供值的值。 " >= ":查找大于或等于提供值的值。 " <= ":查找值小于或等于提供的值。 " - ":在两个提供值之间查找值。阅读文档以获得更多信息。 " != ":查找值不等于所提供的值。 | |
between | “-”符号用于在两个值之间选择结果。值应该仅为数字。 |
如关键词模糊查询,搜索用户名称,增加getUserByName()函数,代码如下:
/**
* 模糊查询用户名
* @param {Object} name
*/
getUserByName(name){
return connection.select({
from: this.tableName,
where: {
username: {
like: `%${name}%`
}
}
});
}
如查询创建时间范围值,在getUserByName()函数中where增加between,代码如下:
/**
* 模糊查询用户名,并指定创建时间范围
* @param {Object} param
*/
getUserByNames(param){
let nameParam = {};
//模糊查询
if(param['name']){
nameParam['like'] = `%${param.name}%`;
}
//时间范围
if(Array.isArray(param['timeArray'])&¶m['timeArray'].length==2){
nameParam['-'] = param.timeArray;
}
return connection.select({
from: this.tableName,
where: {
username: nameParam
}
});
}
/**
此时select结构如下图:
{
from: "Users"
where: {
username: {
-: [
Wed Dec 07 2022 18:30:11 GMT+0800 (中国标准时间) {},
Thu Dec 08 2022 18:30:11 GMT+0800 (中国标准时间) {}
],
like: "%王三%"
}
}
}
*/
3.4 插入数据
插入API用于在表中插入新记录.
名称 | 类型 | 描述 |
---|---|---|
upsert | Boolean | upsert用于替换现有数据,如果不存在则插入为新记录。upsert是insert api中的一个选项。 |
用里使用创建用户为例,并且新增用户的密码需要使用md5进行加密处理,代码如下:
/**
* 添加用户数据
* @param {Object} data
*/
insertUser(data){
//增加创建和更新时间
Object.assign(data, {
createtime: new Date(),
updatetime: new Date()
});
//加密密码
data['password'] = hex_md5(data.password);
//插入数据
return connection.insert({
into: this.tableName,
values: [data]
})
}
3.5 修改用户数据
update用于修改表中的现有记录。你可以使用where with update来过滤目标记录。
名称 | 类型 | 描述 |
---|---|---|
with operators | 一些算术运算符可用于更新数据。 例:比如说,你想在产品表的价格列上加5 | |
mapSet | Function | mapSet提供了一种将更新查询中的设置值转换为存储值的方法。 它是一个使用setValue和storedValue调用的函数。 |
例如修改用户信息,代码如下:
/**
* 修改用户信息
* @param {Object} id
* @param {Object} data
*/
editUser(id, data){
if(data['password']){
//加密密码
data['password'] = hex_md5(data.password);
}
return connection.update({
in: this.tableName,
set: data,
where: { id }
});
}
3.6 删除用户数据
remove API可用于从表中删除记录。其中可以用来过滤目标记录。
例如删除指定用户信息,代码如下:
/**
* 删除指定用户信息
* @param {Object} id
*/
deleteUser(id){
return connection.remove({
from: this.tableName,
where: { id }
})
}
3.7 记录总数
count API可用于对表中的记录进行计数。您可以使用where来过滤类似于select的结果。
例如查询姓名为“王三”用户有多少,代码如下:
/**
* 统计记录总数
* @param {Object} name
*/
getCount(name){
return connection.count({
from: this.tableName,
where: {
username: {
like: `%${name}%`
}
}
})
}
3.8 并集查询
union API结合两个或多个选择查询的结果并删除重复记录。
例如产品不同价格数据结果的并集查询,代码如下:
var results = await connection.union([
{
from: 'Products',
where: {
price: {
'>': 10
}
}
},
{
from: 'Products',
where: {
price: {
'>': 50
}
}
}
])
3.9 交集查询
intersect API将两个或多个select查询的结果组合在一起,只取查询结果之间的公共记录。
例如产品不同价格数据结果的交集查询,只返回交集数据,代码如下:
var query1= {
from: 'Products',
where: {
price: {
'>': 10
}
}
};
var query2 = {
from: 'Products',
where: {
price: {
'>': 50
}
}
};
var results = await connection.intersect({
queries:[query1,query2]
})
3.10 清空数据表
清除用于从表中删除所有记录。
注:你也可以使用delete api来清除特定表中的记录,但是clear会很快,不会返回已删除记录的数目,而delete会返回已删除记录的数目。
代码如下:
await connection.clear(table_name);
console.log('data cleared successfully');