小程序 自建本地数据库 本地存储

news2024/11/23 19:40:28

大家好哇,我是梦辛工作室的灵,在最近的开发过程中又遇到了一些问题,这次是关于本地存储的,在小程序面进行存储一些数据,本来就依靠小程序的本地储存API 就可以实现,但数据量小还好,如果数据量大那么就不在方便了,主要就没办法查询或批量修改,我这次主要是因为小程序有无网络状态下也需要可以正常运行,所以我想着能不能直接把数据库放在本地算了,就样子就算没有网络也可以正常运行,然后有网络的时候再去做同步就可以,本着这样的想法,我就瞄上了小程序的文件储存API,如果我把我所需要的数据存在JSON里面然后再存在本地文件夹就可以了,然后就按照自己的想法写出来了MxLocalBase,目前已简单实现的数据库的建立、数据表的建立、事务、索引等,由于JS是单线程运行的,所以也就不用担心多线程的问题,下面来看下整体结构:
在这里插入图片描述
核心类就是bin下面的3个文件,util 文件夹里面主要是 用来做文件储存的辅助类,
先简单说明下如何使用吧
这3个类可以自己独立运行,Connect 可以用于管理 DataBase ,DataBase可以用于管理多个Table类
Table类用于管理文件数据
先说Connect的使用方法:

  let curConn = new Connect(wx.getFileSystemManager(), basePath + path);
  let databaseList = curConn.showDataBases(); //获取数据库列表
  curConn.useDataBase(baseName); //选择目前操作的数据库
  let tableList = curConn.showTableList(); //获取当前数据库的数据表列表
  let curDataBase = curConn.getCurDataBase();//获取当前操作的数据库对象 即使 DataBase 类
  curConn.createTable(tableName,options) //创建数据表
  //options 为数据表结构,其格式为:[item ,....]
  //item :{"name":"列名称":, "type":"列类型 目前支持 string,  number,object,boolean" ,
  //  "default":"默认值", "increment":"是否自动增加", "notNull":"是否不为null", 
  //"primaryKey":"是否为主键", "uni":"是否为唯一键", "comment":"说明"} 
 curConn.doAddTableSet(tableName,itemSet);// 数据表添加列 itemSet 和上述 item 一个格式
 curConn.deleteDataBase(databaseName); //删除数据库	 
 curConn.createDataBase(databaseName,error); //创建数据库
 let table = tryConnectTable(tableName); //获取当前数据表对象 即 Table 类
 curConn.deleteTable(tableName); // 删除数据表 

DataBase 的使用方法:

let curDataBase = curConn.getCurDataBase(); //可以这样获取DataBase对象,也可以直接创建
let curDataBase = new DataBase(wx.getFileSystemManager(),databaseName,BasePath);
curDataBase.createTable(tableName,options); // 创建数据表 同上
let curTable = curDataBase.tryConnectTable(tableName); //获取数据表 也同上
DataBase 创建的时候会读取本地的文件夹列表,视为数据表,并创建其数据表对象

Table的使用方法:

let curTable = curDataBase.tryConnectTable(tableName); //获取数据表 也可以直接创建
let curtable = new Table(wx.getFileSystemManager(), tableName, BasePath);
curtable.setAutoCommit(false); // 开启事务
curtable.addTableSet(itemSet); // 添加列,属性同 上item 
curtable.modiftyTableSet(name,itemSet); // 修改列,name 列名称 itemSet属性同 上item 
curtable.deleteTableSet(name); //删除列 name 为列名称

curtable.modifyData(updateData, whereData); //修改数据 updateData 格式为 [{name:"列名",value:"值"}]
// whereData 的格式为: [{name:"列名",type:"比对类型",value:"值"}]
//目前比对在 util里面的 compareMap,并有其对应的判断方法

curtable.modifyDataByPathIndex(updateData, pathIndex, dataIndex)
//修改数据 updateData 格式为 [{name:"列名",value:"值"}]
//pathIndex 为数据所保存的文件索引,文件目前会按1000条数据划分文件,如 data_0.json  pathIndex 就为0
//dataIndex 为数据所在文件的json中的行数,每个数据返回是都会有 pathIndex, dataIndex

curtable.deleteDataByPathIndex({pathIndex, dataIndex}) //删除指定数据

curtable.deleteData(whereData) //删除数据,同上

curtable.selectData(whereData, mapFun, limitData, orderByData) //查询数据 whereData 格式同上 mapFun为自定义方法
//,每查询到合适的数据就会主动调用该方法
//limitData 为 {start:开始行数,count:返回条数}
//orderByData 为排序对象 格式为:[{name:'列名',type:'排序规则,desc 或 asc'},....]

curtable.addData(itemData);//添加的数据,格式为当前数据表结构
curtable.commit();//提交数据,若不开始事务,修改数据后,500ms 后就会自动保存到文件里

好了,然后在和大家讲下原理把,其实核心还是Table 类,其他的都只是用于管理罢了,
Table 类里面的核心结构为

//数据列表
dataJsonList:[
 	{
		path: 'data_0.json', // 文件名称
	    pathIndex: index,	//文件索引
	    data: [], //具体数据
	    read: 0, //读了几次,用于清理内存时,按读取次数清理,越小越容易被清理
	    modify: 0, //修改位,用于保存时判断是否需要重新写入文件
	    primaryKeyIndex:{},	//主键索引映射
	    uniIndex:{}, //唯一键索引映射
	    indexMap:{} //其他索引映射
    }
]
//数据表结构
setJson:[
	{
		"data": [{
			"name": "username",
			"default": "",
			"type": "string",
			"uni": true
		}, {
			"name": "password",
			"default": "",
			"type": "string",
			"uni": false
		}, {
			"name": "showname",
			"type": "string",
			"default": "",
			"uni": false
		}],
		"index": {
			"username": 0,
			"password": 1,
			"showname": 2
		}
	}
]

目前我这边还写了一个微信小程序的展示界面:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码已上传至github ,有兴趣的同学可以去看下,有什么问题还请大佬们多多指教
github传送门
gitee传送门

还是依旧老规矩,上源码:
Connect.js

import FileManager from "../util/FileManager"; 
import DataBase from "./DataBase";

class Connect {

  constructor(manager,BasePath){
    this.fileManmger = new FileManager(manager);
    this.BasePath = BasePath;
    try{
      this.fileManmger.accessSync(BasePath);
    } catch (e){  
      this.fileManmger.mkdirSync({dirPath:BasePath,recursive:true});
    }
    this.connect = 1; 
  }

  checkFileExsites(filePath){
    try{
      this.fileManmger.accessSync(filePath);
    } catch (e){
      return false;
    }
    return true;
  }

  isConnect(){
    return this.connect == 1;
  }

  isSelectDataBase(){
    if(this.databaseName){
      if(!this.database || this.database.databaseName != this.databaseName){
        this.database = new DataBase(this.fileManmger,this.databaseName,this.BasePath);
      }
    }
    return typeof this.databaseName == "string";
  }

  useDataBase(databaseName,create){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    let databasePath = this.BasePath + "/" + databaseName;
    if(!this.checkFileExsites(databasePath)){
      if(create){
        this.fileManmger.mkdirSync({dirPath:databasePath, recursive:true});
      } else {
        throw("数据库:" + databaseName + " 不存在");
      }  
    } 
    this.databaseName = databaseName; 
  }
  
  createDataBase(databaseName,error){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    let databasePath = this.BasePath + "/" + databaseName; 
    if(!this.checkFileExsites(databasePath)){
      this.fileManmger.mkdirSync({dirPath:databasePath, recursive:true});
      this.databaseName = databaseName;
    } else {
      if(error)throw("数据库:" + databaseName + " 已存在,请勿重复创建");
    }
  } 

  deleteDataBase(databaseName){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    let databasePath = this.BasePath + "/" + databaseName;
    if(!this.checkFileExsites(databasePath)){
      throw("数据库:" + databaseName + " 不存在"); 
    }
    this.fileManmger.rmdirSync({dirPath:databasePath,recursive:true});
    if(this.databaseName == databaseName){
      this.databaseName = "";
      this.database = "";
    }
  }

  tryConnectTable(tableName){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    if(!this.isSelectDataBase()){
      throw("当前未选择数据库");
    }  
    return this.database.tryConnectTable(tableName);
  }

  showDataBases(){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    return this.fileManmger.readdirSync({dirPath:this.BasePath});
  }

  showTableList(){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    if(!this.isSelectDataBase()){
      throw("当前未选择数据库");
    }   
    return this.database.showTables();
  }

  doAddTableSet(tableName,itemSet){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    if(!this.isSelectDataBase()){
      throw("当前未选择数据库");
    }  
    return this.database.doAddTableSet(tableName,itemSet);
  }

  getCurDataBase(){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    if(!this.isSelectDataBase()){
      throw("当前未选择数据库");
    } 
    return this.database;
  }

  createTable(tableName,options){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    if(!this.isSelectDataBase()){
      throw("当前未选择数据库");
    } 
    this.database.createTable(tableName,options);
  }

  deleteTable(tableName){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    if(!this.isSelectDataBase()){
      throw("当前未选择数据库");
    } 
    this.database.deleteTable(tableName);
  }

  doShowTableSet(tableName){
    if(!this.isConnect()){
      throw("当前数据库未连接");
    }
    if(!this.isSelectDataBase()){
      throw("当前未选择数据库");
    } 
    return this.database.doShowTableSet(tableName);
  }

  closeConnect(){
    this.connect = 0; 
  }  

}

export default Connect;

DataBase.js

import { log } from "../util/util";
import Table from "./Table";
class DataBase {
  
  tableMap = {}
  tableList = []

  constructor(manager,databaseName,BasePath){
    this.fileManmgerObject = manager; 
    this.databaseName = databaseName;
    this.BasePath = BasePath; 
    this.loadTableList();
  }

  get CurPath(){
    return this.BasePath + "/" + this.databaseName;
  }

  get CurTablePath(){
    return this.BasePath + "/" + this.databaseName + "/" + this.tableName;
  }

  createTable(tableName,options){ 
    let tablePath = this.CurPath + "/" + tableName;
    if(this.tableMap[tableName]){
      throw("已存在数据表:" + tableName + " 请勿重复创建")
    }
    try{
      this.fileManmger.mkdirSync({dirPath:tablePath, recursive:true});  
      this.fileManmger.mkdirSync({dirPath:tablePath + "/set", recursive:true});  
      this.fileManmger.mkdirSync({dirPath:tablePath + "/data", recursive:true});  
      this.fileManmger.mkdirSync({dirPath:tablePath + "/index", recursive:true});  
      if(options){ 
        this.setTableOptions(tableName,options);
      } 
      this.tableMap[tableName] = new Table(this.fileManmger,tableName,this.CurPath);
    } catch (e){ 
      console.log(e)  
    } 
  }

  loadTableList(){
    let tableList = [];
    try{
      tableList = this.fileManmger.readdirSync({dirPath:this.CurPath});
    } catch(e) {
      log(e);
    }
    for(let tableName of tableList){
        this.tableMap[tableName] = new Table(this.fileManmger,tableName,this.CurPath);
    }
    this.tableList = tableList;
  } 

  setTableOptions(tableName,options){
    this.tryConnectTable(tableName);
    this.tableMap[tableName].setTableOptions(options);
  }

  tryConnectTable(tableName){
    if(!this.tableMap[tableName]){
      throw("不存在数据表:" + tableName)
    }
    if(!this.tableMap[tableName].isConnect){
      this.tableMap[tableName] = new Table(this.fileManmger,tableName,this.CurPath);
    }
    return this.tableMap[tableName];
  }

  get fileManmger(){
    return this.fileManmgerObject;
  }

  doAddTableSet(tableName,itemSet){ 
    this.tryConnectTable(tableName);
    return this.tableMap[tableName].addTableSet(itemSet);
  }
   
  showTables(){  
    return this.tableList;
  }
  
  deleteTable(tableName){ 
    let tablePath = this.CurPath + "/" + tableName;
    if(!this.tableMap[tableName]){
      throw("数据表:" + tableName + " 不存在"); 
    } 
    this.fileManmger.rmdirSync({dirPath:tablePath,recursive:true}); 
    this.tableMap[tableName] = {};
    delete this.tableMap[tableName];
    this.tableList.splice(this.tableList.indexOf(tableName),1);
  }

  doShowTableSet(tableName){
    this.tryConnectTable(tableName);
    return this.tableMap[tableName].setJson.data;
  }

}

export default DataBase;

Table.js

import FileManager from "../util/FileManager";
import util from "../util/util"
let typeMap = {
  "string": 1,
  "number": 1,
  "boolean": 1,
  "object": 1
}
let saveSetTimeout = 0;
let saveDataJsonTimeout = 0;
let releaseDataJsonTimeout = 0;
let saveIndexJsonTimeout = 0;
let MaxSaveLines = 1000; //一个文件最大保存1000条数据
let releaseLimitTime = 30 * 1000; // 读取数据 或 保存数据后多少秒清理内存
let releaseSaveCount = 3; // 释放内存数据时 保存数量 按readCount排序来释放
let saveLimitTime = 500;// 每隔500ms 才保存一次
class Table {

  constructor(manager, tableName, BasePath) {
    if (manager instanceof FileManager) {
      this.fileManmgerObject = manager;
    } else {
      this.fileManmgerObject = new FileManager(manager);
    }
    this.tableName = tableName;
    this.BasePath = BasePath;
    this.autoCommit = true;
    this.connect();
  }

  setAutoCommit(autoCommit) {
    this.autoCommit = autoCommit;
  }

  connect() {
    if (this.isConnect) {
      return true;
    }
    try {
      this.fileManmger.accessSync(this.CurPath);
    } catch (e) {
      throw ("当前数据表不存在");
    }
    this.isConnect = 1;
    this.loadTableSet();
    this.loadTableDataPath();
    this.loadTableIndex();
    return true;
  }

  close() {
    this.checkConnect();
    if (this.autoCommit) {
      this.commit();
    } else {
      this.rollback();
    }
    this.connect = 1;
  }

  get fileManmger() {
    return this.fileManmgerObject;
  }

  get CurPath() {
    return this.BasePath + "/" + this.tableName;
  }

  loadTableSet() {
    this.checkConnect();
    this.setJson = this.readFileSync("/set/set.json", {
      data: [],
      index: {}
    })
  }

  setTableOptions(options) {
    this.checkConnect();
    if (this.setJson.data.length > 0) {
      throw ("当前数据表已存在结构,请勿重复设置");
    }
    let setJson = {
      data: [],
      index: {}
    };
    if (!options.column || typeof options.column[0] != "object") {
      throw ("错误的列表设置");
    }
    let hasPrimaryKey = false;
    for (let item of options.column) {
      if (!item.name) {
        throw ("列表必须含有name字段");
      }
      if (item.autoIncrement && item.type != "number") {
        throw ("自动增加类型只能为数字");
      }
      if (item.primaryKey) {
        if (hasPrimaryKey) {
          throw ("主键仅能有一个字段");
        }
        hasPrimaryKey = true;
      }
      setJson.data.push({
        name: item.name,
        defaultValue: item.defaultValue || undefined,
        autoIncrement: item.autoIncrement || false,
        comment: item.comment || "无",
        type: item.type || "any",
        notNull: item.notNull,
        primaryKey: item.primaryKey || false,
        uni: item.uni
      })
      setJson.index[item.name] = setJson.data.length - 1;
    }
    this.setJson = setJson;
    this.saveSetJson();
  }

  readFileSync(path, defaultValue) {
    let result = defaultValue;
    try {
      let dataPath = this.CurPath + path;
      this.fileManmger.accessSync(dataPath);
      let readData = this.fileManmger.readFileSync({
        filePath: dataPath,
        encoding: "utf-8",
      })
      result = JSON.parse(readData)
    } catch (e) {
      util.log(e);
    }
    return result;
  }

  loadTableDataPath() {
    this.checkConnect();
    try {
      let dataJsonPath = this.CurPath + "/data";
      let resultData = this.fileManmger.readdirSync({ dirPath: dataJsonPath });
      if (!(resultData instanceof Array)) {
        resultData = [];
      }
      let result = [];
      for (let index = 0; index < resultData.length; index++) {
        result.push({
          path: 'data_' + index + '.json',
          pathIndex: index,
          data: [],
          read: 0,
          modify: 0,
        })
      }
      this.dataJsonList = result;
    } catch (e) {
      util.log(e);
      this.dataJsonList = [];
    }
  }

  /**
   * 
   * @param {
   *    name:"字段名称",
   *    type:"字段类型",
   *    primaryKey:"是否为主键",
   *    default:"默认值",
   *    uni:"是否为唯一键"
   * } itemSet 字段属性
   */
  addTableSet(itemSet) {
    this.checkConnect();
    this.checkItemSet(itemSet);
    let setJson = this.setJson;
    if (typeof setJson.index[itemSet.name] == "number") {
      throw ("当前字段已存在,请勿重复创建");
    }
    if (itemSet.uni && typeof itemSet.default != "undefined") {
      throw ("唯一键默认值仅能为undefined");
    }
    for (let item of setJson.data) {
      if (itemSet.primaryKey && item.primaryKey) {
        throw ("已存在主键");
      }
    }
    let dataJsonList = this.dataJsonList;
    for (let dataJson of dataJsonList) {
      this.loadDataJson(dataJson);
      let index = 0;
      for (let item of dataJson.data) {
        if (typeof itemSet.default == "undefined") {
          item[itemSet.name] = undefined;
        } else {
          item[itemSet.name] = itemSet.default;
          if (dataJson.indexMap[itemSet.name]) {
            if (!dataJson.indexMap[itemSet.name][itemSet.default]) {
              dataJson.indexMap[itemSet.name][itemSet.default] = [index];
            } else {
              dataJson.indexMap[itemSet.name][itemSet.default].push(index);
            }
          }
        }
        index++;
      }
      dataJson.modify = 1;
    }
    setJson.data.push(itemSet);
    setJson.index[itemSet.name] = setJson.data.length - 1;
    this.saveSetJson(setJson);
    this.commit();
  }

  modiftyTableSet(name, itemSet) {
    this.checkConnect();
    this.checkItemSet(itemSet);
    let setJson = this.setJson;
    if (typeof setJson.index[name] != "number") {
      throw ("修改字段不存在");
    }
    if (typeof setJson.index[itemSet.name] != "number") {
      throw ("目标字段已存在,请勿重复创建");
    }
    if (itemSet.uni && typeof itemSet.default != "undefined") {
      throw ("唯一键默认值仅能为undefined");
    }
    if (itemSet.primaryKey && typeof setJson.index.primaryKey) {
      throw ("当前表已存在主键");
    }
    let isIndex = false;
    if (this.indexJsonMap[srcSetJson.name]) {
      isIndex = true;
    }
    let dataJsonList = this.dataJsonList;
    for (let dataJson of dataJsonList) {
      this.loadDataJson(dataJson);
      let indexMap = {};
      let index = 0;
      for (let item of dataJson.data) {
        let tempValue = item[name];
        if (typeof tempValue == "undefined") {
          item[itemSet.name] = itemSet.default;
        } else {
          item[itemSet.name] = tempValue;
          indexMap[tempValue] = index;
          if (dataJson.indexMap[itemSet.name]) {
            if (!dataJson.indexMap[itemSet.name][tempValue]) {
              dataJson.indexMap[itemSet.name][tempValue] = [index];
            } else {
              dataJson.indexMap[itemSet.name][tempValue].push(index);
            }
          }
        }
        if (isIndex) {
          delete dataJson.indexMap[itemSet.name];
        }
        delete item[name];
        index++;
      }
      if (itemSet.primaryKey) {
        dataJson.primaryKey = indexMap;
      } else if (itemSet.uni) {
        dataJson.uniIndex[itemSet.name] = indexMap;
        delete dataJson.uniIndex[name];
      }
      if (srcSetJson.uni) {
        delete dataJson.uniIndex[name];
      } else if (srcSetJson.primaryKey) {
        dataJson.primaryKey = {};
      }

      dataJson.modify = 1;
    }
    setJson.data.splice(setJson.index[name], 1);
    setJson.data.push(itemSet);
    this.reIndexSetJson(setJson);
    this.saveSetJson(setJson);
    this.commit();
  }

  deleteTableSet(name) {
    this.checkConnect(); 
    let setJson = this.setJson;
    if (typeof setJson.index[name] != "number") {
      throw ("删除字段不存在");
    }
    let srcSetJson = setJson.data[setJson.index[name]];
    let dataJsonList = this.dataJsonList;
    let isIndex = false;
    if (this.indexJsonMap[srcSetJson.name]) {
      isIndex = true;
    }
    for (let dataJson of dataJsonList) {
      this.loadDataJson(dataJson);
      for (let item of dataJson.data) {
        delete item[name];
      }
      if (srcSetJson.uni) {
        delete dataJson.uniIndex[name];
      }
      if (srcSetJson.primaryKey) {
        dataJson.primaryKeyIndex = {};
      }
      if (isIndex) {
        delete dataJson.indexMap[itemSet.name];
      }
      dataJson.modify = 1;
    }
    setJson.data.splice(setJson.index[name], 1);
    this.reIndexSetJson(setJson);
    this.saveSetJson(setJson);
    this.commit();
  }

  checkConnect() {
    if (!this.isConnect) {
      throw ("未连接当前数据表")
    }
  }

  checkItemSet(itemSet) {
    if (!itemSet.name) {
      throw ("列表必须含有name字段");
    }
    if (!itemSet.type) {
      throw ("列表必须设置type字段");
    }
    if (!typeMap[itemSet.type]) {
      throw ("type只能为:string、number、boolean、object");
    }
    if (itemSet.autoIncrement && itemSet.type != "number") {
      throw ("自动增加类型只能为数字");
    }
  }

  saveSetJson() {
    if (saveSetTimeout) {
      clearTimeout(saveSetTimeout);
    }
    saveSetTimeout = setTimeout(() => {
      this.fileManmger.writeFileSync({
        filePath: this.CurPath + "/set/set.json",
        data: JSON.stringify(this.setJson),
        encoding: "utf-8"
      })
      util.log("保存setJson")
      util.log(this.setJson)
    }, saveLimitTime)
  }

  saveDataJson(dataJson) {
    this.fileManmger.writeFileSync({
      filePath: this.CurPath + "/data/" + dataJson.path,
      data: JSON.stringify(dataJson),
      encoding: "utf-8"
    })
    util.log("保存dataJson")
    util.log(dataJson)
  }

  doSaveDataJson() {
    if (saveDataJsonTimeout) {
      clearTimeout(saveDataJsonTimeout);
    }
    saveDataJsonTimeout = setTimeout(() => {
      let dataJsonList = this.dataJsonList;
      for (let dataJson of dataJsonList) {
        if (dataJson.modify && dataJson.read) {
          this.saveDataJson({
            data: dataJson.data,
            path: dataJson.path,
            primaryKeyIndex: dataJson.primaryKeyIndex,
            uniIndex: dataJson.uniIndex,
            indexMap: dataJson.indexMap || {}
          });
          dataJson.modify = 0;
        }
      }
      this.releaseDataJson();
    }, saveLimitTime)
  }
  /**
   * 读取数据文件
   * @param {*} path 
   */
  readDataJson(path) {
    let result = this.readFileSync('/data/' + path, {
      data: [],
      primaryKeyIndex: {},
      uniIndex: {},
      indexMap: {}
    });
    this.releaseDataJson();
    return result;
  }




  /**
   * 重置表结构索引
   * @param {*} setJson 
   */
  reIndexSetJson(setJson) {
    let indexMap = {};
    let index = 0;
    for (let item of setJson.data) {
      indexMap[item.name] = index;
      index++;
    }
    setJson.index = indexMap;
  }
  /**
   * 修改数据
   * @param {*} updateData {name:"列名",value:"值"}
   * @param {*} whereData  {name:"列名",type:"比对类型",value:"值"}
   */
  modifyData(updateData, whereData) {
    if (!updateData || !(updateData instanceof Array)) {
      throw ("更新数据格式不正确");
    }
    let primaryKeyValue = undefined;
    let uniList = [];
    for (let updateJson of updateData) {
      let itemIndex = this.setJson.index[updateJson.name];
      if (typeof itemIndex != "number") {
        throw ("未知列 " + updateJson.name);
      }
      let item = this.setJson.data[itemIndex];
      if (item.primaryKey) {
        if (!updateJson.value) {
          throw ("主键 " + item.name + " 不能为空")
        } else {
          primaryKeyValue = updateJson.value;
        }
      }
      if (item.uni) {
        if (typeof updateJson.value == "undefined") {
          throw ("唯一键 " + item.name + " 不能为空")
        } else {
          uniList.push({
            name: item.name,
            value: updateJson.value
          });
        }
      }
      if (updateJson.value && typeof updateJson.value != item.type) {
        throw ("字段 " + item.name + " 类型不匹配 " + item.type)
      }
    }
    this.checkSaveValue(primaryKeyValue, uniList);
    let modifyCount = 0;
    this.selectData(whereData, (dataJson, curIndex, targetValue) => {
      for (let updateJson of updateData) {
        let itemIndex = this.setJson.index[updateJson.name];
        let setItem = this.setJson.data[itemIndex];
        if (setItem.primaryKey) {
          delete dataJson.primaryKeyIndex[targetValue[setItem.name]];
          dataJson.primaryKeyIndex[updateJson.value] = curIndex;
        } else if (setItem.uni) {
          delete dataJson.uniIndex[setItem.name][targetValue[setItem.name]];
          dataJson.uniIndex[setItem.name][updateJson.value] = curIndex;
        }
        if (this.indexJsonMap[setItem.name]) {
          delete dataJson.indexMap[setItem.name][targetValue[setItem.name]];
          if (dataJson.indexMap[setItem.name][updateJson.value] instanceof Array) {
            dataJson.indexMap[setItem.name][updateJson.value].push(curIndex);
          } else {
            dataJson.indexMap[setItem.name][updateJson.value] = [curIndex];
          }
        }
        targetValue[updateJson.name] = updateJson.value;
      }
      dataJson.modify = 1;
      modifyCount++;
    })
    if (modifyCount > 0) {
      if (this.autoCommit) {
        this.commit();
      }
    }
    return modifyCount;
  }
  /**
  * 修改数据
  * @param {*} updateData {name:"列名",value:"值"} 
  */
  modifyDataByPathIndex(updateData, pathIndex, dataIndex) {
    if (!updateData || !(updateData instanceof Array)) {
      throw ("更新数据格式不正确");
    }
    console.log(updateData);
    let primaryKeyValue = undefined;
    let uniList = [];
    for (let updateJson of updateData) {
      let itemIndex = this.setJson.index[updateJson.name];
      if (typeof itemIndex != "number") {
        throw ("未知列 " + updateJson.name);
      }
      let item = this.setJson.data[itemIndex];
      if (item.primaryKey) {
        if (!updateJson.value) {
          throw ("主键 " + item.name + " 不能为空")
        } else {
          primaryKeyValue = updateJson.value;
        }
      } else if (item.uni) {
        if (typeof updateJson.value == "undefined") {
          throw ("唯一键 " + item.name + " 不能为空")
        } else {
          uniList.push({
            name: item.name,
            value: updateJson.value
          });
        }
      }
      if (updateJson.value && typeof updateJson.value != item.type) {
        throw ("字段 " + item.name + " 类型不匹配 " + item.type)
      }
    }
    this.checkSaveValue(primaryKeyValue, uniList);
    let modifyCount = 0;
    let dataJson = this.dataJsonList[pathIndex];
    let curIndex = dataIndex;
    this.loadDataJson(dataJson);
    let targetValue = dataJson.data[dataIndex];
    if (!targetValue || targetValue.__delete) {
      return modifyCount;
    }
    for (let updateJson of updateData) {
      let itemIndex = this.setJson.index[updateJson.name];
      let setItem = this.setJson.data[itemIndex];
      if (setItem.primaryKey) {
        delete dataJson.primaryKeyIndex[targetValue[setItem.name]];
        dataJson.primaryKeyIndex[updateJson.value] = curIndex;
      } else if (setItem.uni) {
        delete dataJson.uniIndex[setItem.name][targetValue[setItem.name]];
        dataJson.uniIndex[setItem.name][updateJson.value] = curIndex;
      }
      if (this.indexJsonMap[setItem.name]) {
        delete dataJson.indexMap[setItem.name][targetValue[setItem.name]];
        if (dataJson.indexMap[setItem.name][updateJson.value] instanceof Array) {
          dataJson.indexMap[setItem.name][updateJson.value].push(curIndex);
        } else {
          dataJson.indexMap[setItem.name][updateJson.value] = [curIndex];
        }
      }
      targetValue[updateJson.name] = updateJson.value;
      dataJson.data[dataIndex] = targetValue; 
    }
    dataJson.modify = 1;
    modifyCount++;
    if (modifyCount > 0) {
      if (this.autoCommit) {
        this.commit();
      }
    }
    return modifyCount;
  }
  deleteDataByPathIndex({pathIndex, dataIndex}) {
    if(typeof pathIndex != "number"){
      throw("缺少参数pathIndex");
    }
    if(typeof dataIndex != "number"){
      throw("缺少参数dataIndex");
    }
    let deleteCount = 0;
    this.checkConnect();
    let dataJson = this.dataJsonList[pathIndex];
    this.loadDataJson(dataJson);
    if (dataJson.data[dataIndex]) {
      let targetValue = dataJson.data[dataIndex];
      for (let setItem of this.setJson.data) {
        if (setItem.primaryKey) {
          delete dataJson.primaryKeyIndex[targetValue[setItem.name]];
        } else if (setItem.uni) {
          delete dataJson.uniIndex[setItem.name][targetValue[setItem.name]];
        }
        if (this.indexJsonMap[setItem.name]) {
          let targetIndex = dataJson.indexMap[setItem.name][targetValue[setItem.name]].indexOf(curIndex);
          if (targetIndex > -1) {
            dataJson.indexMap[setItem.name][targetValue[setItem.name]].splice(targetIndex, 1);
          }
        }
        dataJson.data[dataIndex] = {
          __delete: 1
        }
      }
      dataJson.modify = 1;
      deleteCount++;
    }
    if (dataJson.modify) {
      if (this.autoCommit) {
        this.commit();
      }
    }
    return deleteCount;
  }
  /**
   * 删除数据
   * @param {*} whereData {name:"列名",type:"比对类型",value:"值"}
   */
  deleteData(whereData) {
    let deleteCount = 0;
    this.selectData(whereData, (dataJson, curIndex, targetValue) => {
      dataJson.data[curIndex] = {
        __delete: 1
      };
      dataJson.modify = 1;
      for (let setItem of this.setJson.data) {
        if (setItem.primaryKey) {
          delete dataJson.primaryKeyIndex[targetValue[setItem.name]];
        } else if (setItem.uni) {
          delete dataJson.uniIndex[setItem.name][targetValue[setItem.name]];
        }
        if (this.indexJsonMap[setItem.name]) {
          let targetIndex = dataJson.indexMap[setItem.name][targetValue[setItem.name]].indexOf(curIndex);
          if (targetIndex > -1) {
            dataJson.indexMap[setItem.name][targetValue[setItem.name]].splice(targetIndex, 1);
          }
        }
      }
      deleteCount++;
    })
    if (deleteCount > 0) {
      if (this.autoCommit) {
        this.commit();
      }
    }
    return deleteCount;
  }

  loadDataJson(dataJson) {
    if (!dataJson.read) {
      let { data, primaryKeyIndex, uniIndex, indexMap } = this.readDataJson(dataJson.path);
      dataJson.data = data;
      dataJson.primaryKeyIndex = primaryKeyIndex;
      dataJson.uniIndex = uniIndex;
      dataJson.read = 1;
      if (!indexMap) { indexMap = {}; }
      dataJson.indexMap = indexMap;
      let indexJsonMap = this.indexJsonMap;
      for (let key in indexJsonMap) {
        if (!indexMap[key]) {
          indexMap[key] = {};
          let index = 0;
          for (let targetData in dataJson.data) {
            if (!(indexMap[key][targetData[key]] instanceof Array)) { indexMap[key][targetData[key]] = [] }
            indexMap[key][targetData[key]].push(index);
            index++;
          }
          dataJson.modify = 1;
        }
      }
      for (let key in indexMap) {
        if (!indexJsonMap[key]) {
          delete indexMap[key];
          dataJson.modify = 1;
        }
      }
    }
    if (typeof dataJson.readCount != "number") {
      dataJson.readCount = 0;
    }
    dataJson.readCount++;
    if (dataJson.modify) {
      this.saveDataJson({
        data: dataJson.data,
        path: dataJson.path,
        primaryKeyIndex: dataJson.primaryKeyIndex,
        uniIndex: dataJson.uniIndex,
        indexMap: dataJson.indexMap || {}
      });
    }
  }

  /**
   * 查询数据
   * @param {*} whereData [{name:"列名",type:"比对类型",value:"值"}]
   * @return 目前返回的都是对象,即实际是地址,不可以直接修改,需深拷贝后再直接修改,不然容易发生错误
   */
  selectData(whereData, mapFun, limitData, orderByData) {
    if (!(whereData instanceof Array)) {
      throw ("whereData必须为数组");
    } 
    this.checkConnect();
    let resultSelect = [];
    let setJson = this.setJson;
    let { primaryKeyWhere, uniKeyWhere, indexKeyWhere, otherKeyWhere,
      primaryEqualKeyWhere, uniEqualKeyWhere, indexEqualKeyWhere } = this.parseWhereArray(whereData, setJson);

    for (let dataJson of this.dataJsonList) {
      this.loadDataJson(dataJson);
      this.filterAllWhere(dataJson, {
        primaryKeyWhere, indexKeyWhere, otherKeyWhere, uniKeyWhere, primaryEqualKeyWhere, uniEqualKeyWhere, mapFun, indexEqualKeyWhere
      }, resultSelect);
      if ((!orderByData || orderByData.length == 0) && limitData && typeof limitData.count == "number") {
        if (!limitData.start) {
          limitData.start = 0;
        }
        if (resultSelect.length > limitData.start + limitData.count) {
          resultSelect = resultSelect.slice(limitData.start, limitData.start + limitData.count);
          break;
        }
      }
    }
    if (orderByData && orderByData.length > 0) {
      resultSelect.sort((a, b) => {
        for (let orderby of orderByData) {
          if(a[orderby.name] != b[orderby.name]){
            return orderby.type == "desc"?(b[orderby.name] - a[orderby.name]):(a[orderby.name] - b[orderby.name]);
          }
        }
        if(a.__pathIndex != b.__pathIndex){
          return a.__pathIndex - b.__pathIndex;
        }
        return a.__index - b.__index;
      });
      if (limitData && typeof limitData.count == "number") {
        if (!limitData.start) {
          limitData.start = 0;
        } 
        resultSelect = resultSelect.slice(limitData.start, limitData.start + limitData.count); 
      }
    }
    return resultSelect;
  }

  filterAllWhere(dataJson, {
    primaryKeyWhere, indexKeyWhere, indexEqualKeyWhere = [], otherKeyWhere,
    uniKeyWhere, primaryEqualKeyWhere, uniEqualKeyWhere, mapFun
  }, resultSelect) {
    if (primaryEqualKeyWhere.value) {
      let dataIndex = dataJson.primaryKeyIndex[primaryEqualKeyWhere.value];
      if (typeof dataIndex == "number") {
        let targetValue = dataJson.data[dataIndex];
        if (targetValue && !targetValue.__delete) {
          targetValue.__index = dataIndex;
          targetValue.__pathIndex = dataJson.pathIndex;
          if (this.checkValueWhere(targetValue, [...indexKeyWhere, ...indexEqualKeyWhere, ...uniKeyWhere, ...otherKeyWhere, ...primaryKeyWhere])) {
            resultSelect.push(targetValue);
            typeof mapFun == "function" && mapFun(dataJson, dataIndex, targetValue);
          }
        }
      }
    } else if (primaryKeyWhere.value) {
      let primaryKeyIndex = dataJson.primaryKeyIndex;
      let resultIndex = [];
      for (let value in primaryKeyIndex) {
        if (util.compare(value, primaryKeyWhere.type, primaryKeyWhere.value)) {
          resultIndex.push(primaryKeyWhere[value]);
        }
      }
      for (let dataIndex of resultIndex) {
        let targetValue = dataJson.data[dataIndex];
        if (targetValue && !targetValue.__delete) {
          targetValue.__index = dataIndex;
          targetValue.__pathIndex = dataJson.pathIndex;
          if (this.checkValueWhere(targetValue, [...indexKeyWhere, ...indexEqualKeyWhere, ...uniKeyWhere, ...uniEqualKeyWhere, ...otherKeyWhere])) {
            resultSelect.push(targetValue);
            typeof mapFun == "function" && mapFun(dataJson, dataIndex, targetValue);
          }
        }
      }
    } else if (uniEqualKeyWhere.length > 0) {
      let uniArrayIndex = undefined;
      for (let uniWhere of uniEqualKeyWhere) {
        let curUniIndex = dataJson.uniIndex[uniWhere.name][uniWhere.value];
        if (typeof curUniIndex != "number") {
          uniArrayIndex = undefined;
          break;
        }
        if (uniArrayIndex == undefined) {
          uniArrayIndex = curUniIndex;
        } else {
          if (uniArrayIndex != curUniIndex) {
            uniArrayIndex = undefined;
            break;
          }
        }
      }
      if (typeof uniArrayIndex == "number") {
        let targetValue = dataJson.data[uniArrayIndex];
        if (targetValue && !targetValue.__delete) {
          targetValue.__index = uniArrayIndex;
          targetValue.__pathIndex = dataJson.pathIndex;
          if (this.checkValueWhere(targetValue, [...indexKeyWhere, ...indexEqualKeyWhere, ...uniKeyWhere, ...otherKeyWhere])) {
            resultSelect.push(targetValue);
            typeof mapFun == "function" && mapFun(dataJson, uniArrayIndex, targetValue);
          }
        }
      }
    } else if (uniKeyWhere.length > 0) {
      let uniArrayIndex = undefined;
      for (let uniWhere of uniKeyWhere) {
        let curUniIndex = dataJson.uniIndex[uniWhere.name];
        if (typeof curUniIndex == "undefined" || curUniIndex.length == 0) {
          break;
        }
        let filterIndex = [];
        for (let value in curUniIndex) {
          if (util.compare(value, uniWhere.type, uniWhere.value)) {
            filterIndex.push(curUniIndex[value]);
          }
        }
        if (uniArrayIndex == undefined) {
          uniArrayIndex = filterIndex;
          continue;
        } else {
          uniArrayIndex = uniArrayIndex.filter(a => {
            return filterIndex.indexOf(a) >= 0;
          })
        }
        if (uniArrayIndex.length == 0) {
          break;
        }
      }
      if (uniArrayIndex && uniArrayIndex.length > 0) {
        for (let index of uniArrayIndex) {
          let targetValue = dataJson.data[index];
          if (targetValue && !targetValue.__delete) {
            targetValue.__index = index;
            targetValue.__pathIndex = dataJson.pathIndex;
            if (this.checkValueWhere(targetValue, [...indexEqualKeyWhere, ...indexKeyWhere, ...otherKeyWhere])) {
              resultSelect.push(targetValue);
              typeof mapFun == "function" && mapFun(dataJson, index, targetValue);
            }
          }
        }
      }
    } else if (indexEqualKeyWhere.length > 0) {
      let indexMap = dataJson.indexMap;
      let curIndexArray = undefined;
      for (let indexEqualKey of indexEqualKeyWhere) {
        if (!indexMap[indexEqualKey.name]) {
          continue;
        }
        if (!curIndexArray) {
          curIndexArray = indexMap[indexEqualKey.name][indexEqualKey.value] || [];
        } else {
          let filterIndex = indexMap[indexEqualKey.name][indexEqualKey.value] || [];
          curIndexArray = curIndexArray.filter(item => {
            return filterIndex.indexOf(item) > -1;
          })
        }
      }
      if (curIndexArray && curIndexArray.length > 0) {
        for (let curIndex of curIndexArray) {
          let targetValue = dataJson.data[curIndex];
          if (targetValue && !targetValue.__delete) {
            targetValue.__index = curIndex;
            targetValue.__pathIndex = dataJson.pathIndex;
            if (this.checkValueWhere(targetValue, [...indexKeyWhere, ...otherKeyWhere])) {
              resultSelect.push(targetValue);
              typeof mapFun == "function" && mapFun(dataJson, curIndex, targetValue);
            }
          }
        }
      }
    } else if (indexKeyWhere.length > 0) {
      let resultIndex = undefined;
      let indexMap = dataJson.indexMap;
      for (let indexkey of indexKeyWhere) {
        if (!indexMap[indexkey.name]) {
          continue;
        }
        let indexMapValue = indexMap[indexkey.name];
        for (let indexValue in indexMapValue) {
          if (util.compare(indexValue, indexkey.type, indexkey.value)) {
            if (resultIndex == undefined) {
              resultIndex = indexMapValue[indexValue];
            } else {
              resultIndex = resultIndex.filter(item => {
                return indexMapValue[indexValue].indexOf(item) > -1;
              })
              if (resultIndex.length == 0) {
                resultIndex = [];
                break;
              }
            }
          }
        }
      }
      if (resultIndex == undefined) {
        //没有索引列,扫描全表
        let curIndex = 0;
        for (let targetValue of dataJson.data) {
          if (targetValue && !targetValue.__delete) {
            targetValue.__index = curIndex;
            targetValue.__pathIndex = dataJson.pathIndex;
            if (this.checkValueWhere(targetValue, [...indexKeyWhere, ...otherKeyWhere])) {
              resultSelect.push(targetValue);
              typeof mapFun == "function" && mapFun(dataJson, curIndex, targetValue);
            }
          }
          curIndex++;
        }
      } else if (resultIndex.length > 0) {
        //有索引 扫描索引
        for (let curIndex of resultIndex) {
          let targetValue = dataJson.data[curIndex];
          if (targetValue && !targetValue.__delete) {
            targetValue.__index = curIndex;
            targetValue.__pathIndex = dataJson.pathIndex;
            if (this.checkValueWhere(targetValue, [...otherKeyWhere])) {
              resultSelect.push(targetValue);
              typeof mapFun == "function" && mapFun(dataJson, curIndex, targetValue);
            }
          }
        }
      }
    } else if (otherKeyWhere.length > 0) { 
      let curIndex = 0;
      for (let targetValue of dataJson.data) {  
        if (targetValue && !targetValue.__delete) {
          targetValue.__index = curIndex;
          targetValue.__pathIndex = dataJson.pathIndex;
          if (this.checkValueWhere(targetValue, [...otherKeyWhere])) {
            resultSelect.push(targetValue);
            typeof mapFun == "function" && mapFun(dataJson, curIndex, targetValue);
          }
        }
        curIndex++;
      }
    } else {
      let curIndex = 0;
      for (let targetValue of dataJson.data) { 
        if (targetValue && !targetValue.__delete) {
          targetValue.__index = curIndex;
          targetValue.__pathIndex = dataJson.pathIndex;
          resultSelect.push(targetValue);
          typeof mapFun == "function" && mapFun(dataJson, curIndex, targetValue);
        } 
        curIndex++;
      }
    }
  }

  checkValueWhere(value, whereArr) {
    let result = true;
    for (let item of whereArr) {
      if (!util.compare(value[item.name], item.type, item.value)) {
        result = false;
        break;
      }
    }
    return result;
  }

  /**
   * 添加数据
   * @param {*} itemData 添加的数据
   */
  addData(itemData) {
    this.checkConnect();
    let setData = this.setJson.data;
    if (!setData.autoIncrementIndex) {
      setData.autoIncrementIndex = {};
    }
    let addJson = {};
    let primaryKeyValue = undefined;
    let uniList = [];
    for (let item of setData) {
      if (item.primaryKey) {
        if (!itemData[item.name] && !item.autoIncrement) {
          throw ("主键 " + item.name + " 不能为空")
        } else if (!itemData[item.name]) {
          primaryKeyValue = (setData.autoIncrementIndex[item.name] || 0) + 1;
          setData.autoIncrementIndex[item.name] = primaryKeyValue;
          itemData[item.name] = primaryKeyValue;
          setData.modify = 1;
        } else {
          primaryKeyValue = itemData[item.name];
        }
      } else if (item.uni) {
        if (!itemData[item.name]) {
          throw ("唯一键 " + item.name + " 不能为空")
        } else {
          uniList.push({
            name: item.name,
            value: itemData[item.name]
          });
        }
      } else if (item.autoIncrement && !itemData[item.name]) {
        itemData[item.name] = (setData.autoIncrementIndex[item.name] || 0) + 1;
        setData.autoIncrementIndex[item.name] = itemData[item.name];
        setData.modify = 1;
      }
      if (itemData[item.name] && typeof itemData[item.name] != item.type) {
        throw ("字段 " + item.name + " 类型不匹配 " + item.type)
      }
      if (typeof itemData[item.name] != "undefined") {
        addJson[item.name] = itemData[item.name];
      } else {
        addJson[item.name] = item.default;
      }
    }
    let curDataJson = this.getCurDataJson();
    this.checkSaveValue(primaryKeyValue, uniList);
    curDataJson.data.push(addJson);
    let curAddIndex = curDataJson.data.length - 1;
    if (typeof primaryKeyValue != "undefined") {
      curDataJson.primaryKeyIndex[primaryKeyValue] = curAddIndex;
    }
    for (let uni of uniList) {
      if (!curDataJson.uniIndex[uni.name]) {
        curDataJson.uniIndex[uni.name] = {};
      }
      if (typeof uni.value != "undefined") {
        curDataJson.uniIndex[uni.name][uni.value] = curAddIndex;
      }
    }
    let indexMap = curDataJson.indexMap;
    if (!indexMap) {
      curDataJson.indexMap = {};
      indexMap = curDataJson.indexMap;
    }
    for (let indexName in indexMap) {
      if (indexMap[indexName]) {
        indexMap[indexName].push(curAddIndex);
      }
    }
    curDataJson.modify = 1;
    if (this.autoCommit) {
      this.commit();
      if (this.setJson.modify == 1) {
        this.saveSetJson();
      }
    }
  }

  /**
   * 检查主键和唯一键是否冲突
   * @param {*} primaryKeyValue 主键
   * @param {*} uniList 唯一键 {键名:值}
   */
  checkSaveValue(primaryKeyValue, uniList) {
    if (!primaryKeyValue && !uniList) {
      return;
    }
    let dataJsonList = this.dataJsonList;
    for (let dataJson of dataJsonList) {
      this.loadDataJson(dataJson);
      if (typeof primaryKeyValue != "undefined" && typeof dataJson.primaryKeyIndex[primaryKeyValue] == "number") {
        throw ("主键 " + value + " 已存在,请勿重复添加")
      }
      if (uniList instanceof Array) {
        for (let uni of uniList) {
          if (dataJson.uniIndex[uni.name] && typeof dataJson.uniIndex[uni.name][uni.value] == "number") {
            throw ("唯一键 " + uni.name + " 值 " + uni.value + " 已存在,请勿重复添加")
          }
        }
      }
      if (!dataJson.readCount) {
        dataJson.readCount = 1;
      } else {
        dataJson.readCount++;
      }
    }
  }

  /**
   * 获取最新的数据对象
   */
  getCurDataJson() {
    if (this.dataJsonList.length == 0) {
      let curDataJson = {
        path: 'data_0.json',
        data: [],
        read: 1,
        modify: 0,
        primaryKeyIndex: {},
        uniIndex: {}
      };
      this.dataJsonList.push(curDataJson);
      return curDataJson;
    }
    let curDataJson = this.dataJsonList[this.dataJsonList.length - 1];
    if (curDataJson.data.length >= MaxSaveLines) {
      let curIndex = this.dataJsonList.length;
      curDataJson = {
        path: 'data_' + curIndex + '.json',
        data: [],
        read: 1,
        modify: 0,
        primaryKeyIndex: {},
        uniIndex: {}
      };
      this.dataJsonList.push(curDataJson);
    }
    if (typeof curDataJson.readCount == "undefined") {
      curDataJson.readCount = 0;
    }
    curDataJson.readCount++;
    return curDataJson;
  }

  /**
   * 提交数据
   */
  commit() {
    this.checkConnect();
    this.doSaveDataJson();
  }

  /**
   * 数据回滚 不保存
   */
  rollback() {
    this.checkConnect();
    this.reloadDataJson();
  }

  /**
   * 重载内存数据
   */
  reloadDataJson() {
    let dataJsonList = this.dataJsonList;
    for (let dataJson of dataJsonList) {
      dataJson.read = 0;
      dataJson.modify = 0;
      dataJson.data = [];
      dataJson.readCount = 0;
      dataJson.indexMap = {};
    }
  }

  /**
   * 释放最近不使用的内存数据
   */
  releaseDataJson() {
    let dataJsonList = this.dataJsonList;
    if (dataJsonList.length <= releaseSaveCount) {
      return;
    }
    if (releaseDataJsonTimeout) {
      clearTimeout(releaseDataJsonTimeout)
    }
    releaseDataJsonTimeout = setTimeout(() => {
      let readCountMap = [];
      let index = 0;
      for (let dataJson of dataJsonList) {
        if (dataJson.read && dataJson.modify) {
          index++;
          continue;
        }
        readCountMap.push({
          path: dataJson.path,
          readCount: dataJson.readCount || 0,
          index: index
        })
        index++;
      }
      readCountMap.sort((a, b) => {
        if (a.readCount == b.readCount) {
          return a.index - b.index;
        }
        return a.readCount - b.readCount;
      })
      for (let readIndex = 0; readIndex < readCountMap.length - releaseSaveCount; readIndex++) {
        dataJsonList[readCountMap[readIndex].index].data = [];
        dataJsonList[readCountMap[readIndex].index].modify = 0;
        dataJsonList[readCountMap[readIndex].index].readCount = 0;
        dataJsonList[readCountMap[readIndex].index].read = 0;
        dataJsonList[readCountMap[readIndex].index].primaryKeyIndex = {};
        dataJsonList[readCountMap[readIndex].index].uniIndex = {};
      }
    }, releaseLimitTime);
  }

  /** index 相关操作开始 */

  loadTableIndex() {
    this.checkConnect();
    try {
      let { data } = this.readIndexJson();
      this.indexJsonMap = data;
    } catch (e) {
      util.log(e);
      this.indexJsonMap = {};
      this.saveIndexJson({ data: {} });
    }
  }

  readIndexJson() {
    let result = this.readFileSync('/index/index.json', {
      data: {},
    });
    return result;
  }

  saveIndexJson(indexJson) {
    this.fileManmger.writeFileSync({
      filePath: this.CurPath + "/index/index.json",
      data: JSON.stringify(indexJson),
      encoding: "utf-8"
    })
    util.log("保存indexJson")
  }

  /**
   * 添加索引
   */
  alertAddIndex(name) {
    this.checkConnect();
    if (typeof this.setJson.index[name] != "number") {
      throw ("不存在字段:" + name);
    }
    if (this.indexJsonMap[name]) {
      throw ("已存在索引:" + name);
    } else {
      this.indexJsonMap[name] = 1;
    }
    this.doSaveIndexJson();
  }

  /**
   * 删除索引
   */
  dropIndex(name) {
    this.checkConnect();
    if (typeof this.setJson.index[name] != "number") {
      throw ("不存在字段:" + name);
    }
    let curIndexJsonList = this.indexJsonMap[name];
    if (typeof curIndexJsonList == "undefined") {
      throw ("不存在索引:" + name);
    }
    delete this.indexJsonMap[name];
  }

  doSaveIndexJson() {
    if (saveIndexJsonTimeout) {
      clearTimeout(saveIndexJsonTimeout);
    }
    saveIndexJsonTimeout = setTimeout(() => {
      this.saveIndexJson({ data: this.indexJsonMap });
    }, saveLimitTime);
  }

  /** index 相关操作结束 */

  deleteFile(path) {
    this.fileManmger.unlinkSync({
      filePath: path
    })
  }

  parseWhereArray(whereData, setJson) {
    let primaryKeyWhere = {};
    let primaryEqualKeyWhere = {};
    let uniKeyWhere = [];
    let uniEqualKeyWhere = [];
    let indexKeyWhere = [];
    let otherKeyWhere = [];
    let indexEqualKeyWhere = [];
    for (let item of whereData) {
      if (typeof setJson.index[item.name] != "number") {
        throw ("不存在字段:" + item.name);
      }
      let curSetJson = setJson.data[setJson.index[item.name]];
      if (curSetJson.primaryKey) {
        if (item.type == "=") {
          primaryEqualKeyWhere = item;
        } else {
          primaryKeyWhere = item;
        }
      } else if (curSetJson.uni) {
        if (item.type == "=") {
          uniEqualKeyWhere.push(item);
        } else {
          uniKeyWhere.push(item);
        }
      } else if (typeof this.indexJsonMap[item.name] != "undefined") {
        if (item.type == "=") {
          indexEqualKeyWhere.push(item);
        } else {
          indexKeyWhere.push(item);
        }
      } else {
        otherKeyWhere.push(item);
      }
    }
    return {
      primaryKeyWhere,
      uniKeyWhere,
      indexKeyWhere,
      otherKeyWhere,
      uniEqualKeyWhere,
      primaryEqualKeyWhere,
      indexEqualKeyWhere
    }
  }
}


export default Table;

好了,本次分享就到这里,梦辛工作室(let dream is completed)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/600126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python开发:为什么适合SEO

Python开发&#xff1a;为什么适合SEO 在当今互联网上&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;尤为重要。因为通过优化您的网站&#xff0c;在搜索引擎上排名更高可以增加您的网站流量和业务转化率。在这篇文章中&#xff0c;我们将探讨为什么Python是一个优秀的…

SpringMVC重点知识

目录 第一章 SpringMVC概念 0.引言 1.MVC 2.SpringMVC 3.SpringMVC的特点 4.JavaSE、JavaEE、javaME的区别 第二章 Spring MVC的使用 1.SpringMVC的配置 2.web.xml配置 3. 创建当前的请求控制器 4. 创建SpringMVC的配置文件 5.实现对首页index.xml的访问 6.Reques…

总结886

学习目标&#xff1a; 月目标&#xff1a;6月&#xff08;张宇强化10讲&#xff0c;专业课&#xff0c;背诵15篇短文&#xff0c;考研核心词过三遍&#xff09; 周目标&#xff1a;1800线性代数部分并完成错题记录&#xff0c;英语背3篇文章并回诵&#xff0c;检测&#xff0…

Throwable源码

介绍 Throwable类是Java语言中所有错误&#xff08;errors&#xff09;和异常&#xff08;exceptions&#xff09;的父类&#xff0c;直接子类为 Error 和 Exception。只有继承于Throwable的类或子类才能被抛出&#xff0c;还有一种是Java中的throw注解类也可以抛出。 public…

Stub实验

需求 将区域12设置为Stub区域&#xff0c;使区域12的路由设备不受外部链路影响(不接收4/5类LSA&#xff09;降低区域12&#xff08;末梢区域&#xff09;设备压力&#xff0c;还能让区域12的PC1与外部PC3通信 配置步骤 1&#xff09;配置接口信息 - 配置PC的IP地址 - 配置路由…

chatgpt赋能python:Python免费资料全揭秘:入门学习到深入应用

Python免费资料全揭秘&#xff1a;入门学习到深入应用 作为一种最具代表性的动态编程语言&#xff0c;Python在很多领域得到了广泛的应用&#xff0c;因其简单易学、开发效率快等特点而备受开发者的喜爱。如果你刚开始学习Python或是想提高你的Python编程技能&#xff0c;那么…

系统移植-环境搭建

安装系统 在基于ARM处理器的开发板上安装Linux系统 1.移植的目的 不同架构的处理器指令集不兼容&#xff0c;即便是相同的处理器架构&#xff0c;板卡不同驱动代码也不兼容 &#xff1b; Linux是一个通用的内核并不是为某一个特定的处理器架构或板卡设计的&#xff0c;…

【生物力学】《人体骨肌系统生物力学》- 王成焘老师 - 第3章 - 人体运动测量与仿真分析

第2章回到目录后续暂时用不到 文章目录 3.1 概论1. 基于影像的运动捕捉技术2 . 其他运动捕捉技术 3.2 人体运动测量内容与设备3.2.1 人体运动测量内容1. 时间参数2. 空间参数3. 时空参数 3.2.2 运动捕捉系统的主要类型与工作特性1. 运动捕捉系统组成2. 运动捕捉系统主要类型与工…

chatgpt赋能python:用Python做股票分析

用Python做股票分析 在当今的股市中&#xff0c;数据分析和预测已经变得十分重要。Python作为最流行的编程语言之一&#xff0c;不仅易于学习&#xff0c;还有非常强大的数据处理和分析能力。在本文中&#xff0c;我们将探讨如何用Python进行股票分析。 数据收集 要进行股票…

Java网络开发(Tomcat)——遇到的 bug 汇总(持续更新):bug:

目录 引出:bug::bug::bug:Tomcat开发的bug汇总session不能转换成String类型在servlet的if处理流程中&#xff0c;没有加return后端传给jsp的数据&#xff0c;前端jsp不显示jsp的包没有导&#xff0c;用foreach方法的时候报错jsp的forEach方法报错jsp用foreach的时候&#xff0c…

chatgpt赋能python:Python免费软件:提高工作效率的首选

Python免费软件&#xff1a;提高工作效率的首选 Python作为一种易于上手的编程语言&#xff0c;在业界广为流传。而随着Python的发展&#xff0c;也催生了相应的一些免费软件&#xff0c;这些软件能够让用户更好地利用Python编程语言&#xff0c;提高工作效率&#xff0c;创造…

数据存储云安全的 5 大支柱

与任何数据存储系统一样&#xff0c;云也存在相当多的安全风险。领导者不应争论云本身安全或不安全的方式&#xff0c;而应质疑他们是否安全地使用云。 虽然云安全采用组织和云提供商之间的责任共担模式&#xff0c;但归根结底&#xff0c;云环境面临的最大风险是解决方案的错…

对数组中的所有元素进行限值指定的最小值和最大值:超过最大值的元素,则改写为最大值小于最小值的元素,则改写为最小值numpy.clip()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 对数组中的所有元素进行限值 指定的最小值和最大值&#xff1a; 超过最大值的元素&#xff0c;则改写为最大值 小于最小值的元素&#xff0c;则改写为最小值 numpy.clip() [太阳]选择题 请问…

大数据Doris(三十二):HDFS Load和Spark Load的基本原理

文章目录 HDFS Load和Spark Load的基本原理 一、HDFS Load 二、 Spark Load的基本原理 HDFS Load和Spark Load的基本原理 一、HDFS Load HDFS Load主要是将HDFS中的数据导入到Doris中&#xff0c;Hdfs load 创建导入语句&#xff0c;导入方式和Broker Load 基本相同&#…

(字符串 ) 剑指 Offer 05. 替换空格 ——【Leetcode每日一题】

❓剑指 Offer 05. 替换空格 难度&#xff1a;简单 请实现一个函数&#xff0c;把字符串 s 中的每个空格替换成 “%20”。 示例 1&#xff1a; 输入&#xff1a;s “We are happy.” 输出&#xff1a;“We%20are%20happy.” 限制&#xff1a; 0 < s 的长度 < 10000 …

第四章 Electron 使用SQLite3数据库

一、SQLite是什么 &#x1f447; &#x1f447; &#x1f447; SQLite是一种嵌入式关系型数据库管理系统&#xff0c;是一个零配置、无服务器的、自给自足的、事务性的SQL数据库引擎。SQLite是一个轻量级的数据库&#xff0c;可以在各种操作系统上使用&#xff0c;并且支持SQL…

区间预测 | MATLAB实现基于QRCNN-LSTM-Multihead-Attention多头注意力卷积长短期记忆神经网络多变量时间序列区间预测

区间预测 | MATLAB实现基于QRCNN-LSTM-Multihead-Attention多头注意力卷积长短期记忆神经网络多变量时间序列区间预测 目录 区间预测 | MATLAB实现基于QRCNN-LSTM-Multihead-Attention多头注意力卷积长短期记忆神经网络多变量时间序列区间预测效果一览基本介绍模型描述程序设计…

【最小生成树模型】

最小生成树&#xff08;Minimum Spanning Tree&#xff09;模型原理与应用 引言 最小生成树&#xff08;Minimum Spanning Tree&#xff0c;简称MST&#xff09;是图论中的经典问题之一&#xff0c;它在实际应用中有着广泛的应用。本文将介绍最小生成树模型的原理和应用&…

导致无人机倾斜摄影免像控点三维重建中出现模型高程偏差大原因及解决方法探讨

导致无人机倾斜摄影免像控点三维重建中出现模型高程偏差大原因及解决方法探讨 无人机倾斜摄影是一种高效的三维测量技术&#xff0c;可用于建筑物、地形和基础设施等场景的快速、精确测量。然而&#xff0c;在进行无人机倾斜摄影时&#xff0c;出现模型高程偏差大的问题是很常…

梅西生涯数据管理系统(Python+数据库)

文章目录 前言MySQL部分1. 导入数据2. 演示说明 Python部分1. 连接数据库2. 登录界面3. 注册4. 主界面5. 查询用户信息6. 修改密码7. 梅西生涯数据分析8. 主函数 尾声 前言 用 Python MySQL 实现简单的数据分析系统&#xff0c;一起来看看吧&#xff01; 本篇博客主要分为两…