封装前端数据库(indexedDB)
/**
* IndexedDB
*/
const IndexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
/**
* 数据库结构
* 对象空间
*/
const IDB_STRUCTURE = [
// 上传任务
{
IDB_STORE_NAME: "表名",
IDB_STORE_OPTIONS: { keyPath: '主键名', autoIncrement: true },
IDB_STORE_INDEX: [
// 主键 (唯一)
{ name: "主键名", prop: "字段属性", options: { unique: true } },
// 字段名称
{ name: "字段名称", prop: "字段属性", options: { unique: false } },
]
}
];
/**
* IDBInstence
* @class IDBInstence
* @description IDBInstence
*/
class IDBInstence {
/**
* 构造函数
*/
constructor(IDB_NAME = null) {
/**
* 数据库名称
*/
this.IDB_NAME = IDB_NAME || null;
/**
* 数据库版本
*/
this.IDB_VERSION = null;
/**
* 数据库实例
*/
this.IDB_DATABASE = null;
/**
* 是否就绪
*/
this.IDB_READY = false;
}
/**
* 初始化数据库
* @param {string} IDB_NAME
*/
initialization(IDB_NAME = null) {
return new Promise((resolve, reject) => {
// 数据库名称
if (!!IDB_NAME) this.IDB_NAME = IDB_NAME;
// 是否支持indexedDB
if (!!IndexedDB === false) return reject("IndexedDB is not supported.");
// 是否已经开启
// if (this.IDB_READY) return resolve();
if (this.IDB_READY) {
this.IDB_READY = false;
this.IDB_DATABASE?.close();
}
// 打开数据库
let request = IndexedDB.open(this.IDB_NAME, this.IDB_VERSION || undefined);
// 打开成功
request.onsuccess = events => {
// 数据库对象
this.IDB_DATABASE = events.target.result;
// 检查是否有不存在的对象空间
if (IDB_STRUCTURE.findIndex(element => !!this.IDB_DATABASE.objectStoreNames.contains(element.IDB_STORE_NAME) === false) !== -1) {
// 数据库版本升级
this.IDB_VERSION = this.IDB_DATABASE.version + 1;
// 关闭当前连接
this.IDB_DATABASE.close();
// 置空对象
this.IDB_DATABASE = null;
// 回调连接并创建对象空间
this.initialization(IDB_NAME).then(resolve).catch(reject);
} else {
this.IDB_READY = true;
resolve();
}
};
// 打开失败
request.onerror = events => (this.IDB_DATABASE = events.target, reject(events.target));
// 创建对象仓库
request.onupgradeneeded = events => {
// 遍历创建
for (let index = 0; index < IDB_STRUCTURE.length; index++) {
// 当前对象
let element = IDB_STRUCTURE[index];
// 检查对象空间是否存在
if (!!events.currentTarget.result.objectStoreNames.contains(element.IDB_STORE_NAME)) continue;
// 创建并创建主键(idbid)自增
let store = events.currentTarget.result.createObjectStore(element.IDB_STORE_NAME, element.IDB_STORE_OPTIONS);
// 创建字段索引
element.IDB_STORE_INDEX.forEach(itemIndex => store.createIndex(itemIndex.name, itemIndex.prop, itemIndex.options));
}
};
});
}
/**
* 获取表格结构
* @param {*} IDB_STORE_NAME 表名
*/
obtainTableStructure(IDB_STORE_NAME) {
return IDB_STRUCTURE[IDB_STRUCTURE.findIndex(table => table.IDB_STORE_NAME === IDB_STORE_NAME)];
}
}
/**
* IDBInstence
*/
const idbInstence = new IDBInstence();
/**
* IDBKeyRange
*/
const IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
/**
* 数据库结构
* 对象空间
*/
class TableInstence {
/**
* 构造函数
*/
constructor(IDB_STORE_NAME = null) {
/**
* 对象仓库名称
*/
this.IDB_STORE_NAME = IDB_STORE_NAME || null;
/**
* 是否就绪
*/
this.IDB_READY = idbInstence.IDB_READY;
}
/**
* 创建服务
* @param model 模式
*/
createService(model = "readonly") {
return idbInstence.IDB_DATABASE.transaction(this.IDB_STORE_NAME, model).objectStore(this.IDB_STORE_NAME);
}
/**
* 插入一条数据
* @param {Object} data
* @returns
*/
insert(data = {}) {
return new Promise((resolve, reject) => {
// 创建事务
let request = this.createService('readwrite').add(data);
// 插入成功
request.onsuccess = events => resolve(events.target.result);
// 插入失败
request.onerror = () => reject(request.error);
});
}
/**
* 根据主键的值查询数据
* @param {*} idbid 主键的值
* @returns
*/
find(idbid = 0) {
return new Promise((resolve, reject) => {
// 创建事务
let request = this.createService('readonly').get(idbid);
// 查询成功
request.onsuccess = () => !!request.result ? resolve(request.result) : reject(`No data with a primary key of "${idbid}" was found in the "${this.IDB_STORE_NAME}" table`);
// 查询失败
request.onerror = () => reject(request.error);
});
}
/**
* 根据索引的值查询数据
* @param {*} index 索引
* @param {*} value 索引的值
* @returns
*/
findIndex(index = null, value = null) {
return new Promise((resolve, reject) => {
// 创建事务
let request = this.createService('readonly').index(index).get(value);
// 查询成功
request.onsuccess = events => !!events.target.result ? resolve(events.target.result) : reject(`Data with an index(${index}) value of "${value}" was not found in the "${this.IDB_STORE_NAME}" table`);
// 查询失败
request.onerror = () => reject(request.error);
});
}
/**
* 查询全部数据
* @returns
*/
findAll() {
return new Promise((resolve, reject) => {
// 创建事务
let request = this.createService('readonly').getAll();
// 查询成功
request.onsuccess = events => resolve(events.target.result);
// 查询失败
request.onerror = () => reject(request.error);
});
}
/**
* 分页查询数据
* @param {Object} pagination { current: 1, size: 10 }
* @returns
*/
findPagination(pagination = { current: 1, size: 10 }) {
return new Promise((resolve, reject) => {
// 校验页码
if (typeof pagination?.current !== "number") return reject(`Your page parameter "current" is not a valid page number`);
// 校验一页大小
if (typeof pagination?.size !== "number") return reject(`Your page parameter "size" is not a valid page size number`);
// 创建事务
let request = this.createService().openCursor();
// 获取总条数
let countObject = this.createService().count();
// 响应数据
let response = {
// 当前页
current: paging.current,
// 一页大小
size: paging.size,
// 总条数
total: 0,
// 数据列表
list: []
};
// 是否已经回调
let isComplete = false;
// 完成
let complete = () => {
// 请求是否完成
if (isComplete || request.readyState !== "done" || countObject.readyState !== "done") return;
isComplete = true;
resolve(response);
}
// 条数查询完毕
countObject.onsuccess = events => (response.total = events.target.result, complete());
// 是否需要跳转
let advance = response.current > 1;
// 查询成功
request.onsuccess = events => {
// 请求数据
let result = events.target.result;
// 是否有数据
if (!!result) {
// 定位到指定位置
if (!!advance) return (advance = false, result.advance((response.current - 1) * response.size))
// 是否是最后一条数据
if (response.list.length === response.size) return complete();
// 添加到响应
response.list.push(result.value);
// 下一条
result.continue();
} else complete();
};
// 查询失败
request.onerror = () => reject(request.error);
});
}
/**
* 根据条件获取数据
* @param {Object} parameters { current: 页码, size: 页大小, index: "索引", value: "索引值", filters: row => true }
* @returns
*/
obtainFilters(parameters = { current: 1, size: 10, index: null, value: null, filters: row => true }) {
return new Promise((resolve, reject) => {
let options = { current: 1, size: 10, index: null, value: null, filters: row => true };
// 校验页码
if (!!parameters?.current && isFinite(parameters?.current)) options.current = parameters.current;
else return reject(`Your page parameter "current" is not a valid page number`);
// 校验大小
if (!!parameters?.size && isFinite(parameters?.size)) options.size = parameters.size;
else return reject(`Your page parameter "size" is not a valid page size number`);
// 校验索引
if (parameters?.index !== null && parameters?.index !== undefined) options.index = `${parameters.index}`;
// 校验索引值
if (parameters?.value !== null && parameters?.value !== undefined) options.value = parameters.value;
// 校验过滤方法
if (typeof parameters?.filters === "function") options.filters = parameters.filters;
// 创建事务
let request = null;
if (!!options.index) request = this.createService().index(options.index).openCursor(IDBKeyRange.only(options.value));
else request = this.createService().openCursor();
// 响应数据
let response = {
// 当前页
current: options.current,
// 一页大小
size: options.size,
// 总条数
total: 0,
// 数据列表
list: []
};
// 开始下标
let previous = (options.current - 1) * options.size;
// 结束下标
let behind = previous + options.size - 1;
// 查询成功
request.onsuccess = events => {
// 请求数据
let result = events.target.result;
// 是否有数据
if (!!result) {
// 是否满足条件
if (options.filters(result.value)) {
// 添加到响应
if (response.total >= previous && response.total <= behind) response.list.push(result.value);
// 增加条数
response.total += 1;
}
// 下一条
result.continue();
} else resolve(response);
};
// 查询失败
request.onerror = () => reject(request.error);
});
}
/**
* 根据主键的值删除数据
* @param {*} idbid 主键的值
* @returns
*/
delete(idbid = 0) {
return new Promise((resolve, reject) => {
// 创建事务
let request = this.createService('readwrite').delete(idbid);
// 查询成功
request.onsuccess = () => resolve(request.result);
// 查询失败
request.onerror = () => reject(request.error);
});
}
/**
* 根据索引的值删除数据
* @param {*} index 索引
* @param {*} value 索引的值
* @returns
*/
deleteIndex(index = null, value = null) {
return new Promise((resolve, reject) => this.findIndex(index, value).then(result => this.delete(result[idbInstence.obtainTableStructure(this.IDB_STORE_NAME)?.IDB_STORE_OPTIONS.keyPath])).then(resolve).catch(reject));
}
/**
* 根据主键更新数据
* @param {*} idbid 主键
* @param {*} data 更新的值
* @returns
*/
update(idbid = 0, data = {}) {
return new Promise((resolve, reject) => this.find(idbid).then(result => {
// 新数据
let newData = JSON.parse(JSON.stringify(Object.assign(result, data)));
// 创建事务
let request = this.createService("readwrite").put(newData);
// 查询成功
request.onsuccess = () => resolve(newData);
// 查询失败
request.onerror = () => reject(request.error);
}).catch(reject));
}
/**
* 根据索引的值更新数据
* @param {*} index 主键
* @param {*} value 索引的值
* @param {*} data 更新的值
* @returns
*/
updateIndex(index = null, value = null, data = {}) {
return new Promise((resolve, reject) => this.findIndex(index, value).then(result => {
// 新数据
let newData = JSON.parse(JSON.stringify(Object.assign(result, data)));
// 创建事务
let request = this.createService("readwrite").put(newData);
// 查询成功
request.onsuccess = () => resolve(newData);
// 查询失败
request.onerror = () => reject(request.error);
}).catch(reject));
}
}
/**
* 单例实例
*/
const tableInstance = new TableInstence();
/**
* 单例模式
* @returns
*/
const IDBTable = IDB_STORE_NAME => {
tableInstance = new Proxy(new TableInstence(IDB_STORE_NAME), {
/**
* get
* @param {*} target
* @param {*} prop
* @param {*} receiver
* @returns
*/
get(target, prop, receiver) {
// 拦截方法调用
if (typeof target[prop] === 'function') return function (...args) {
// 调用之前判断数据库是否就绪
if (!!idbInstence.IDB_READY === false) return Promise.reject("idbInstence is not ready.");
const result = target[prop].apply(target, args);
// 调用之后
// ()=>{}
return result;
};
// 如果不是方法调用,则直接返回原始属性
else return Reflect.get(target, prop, receiver);
}
});
return tableInstance;
};
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
CaptainTwo!
喜欢就支持一下吧