CloudData.class.js 9.0 KB
Newer Older
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
const dbJQL = uniCloud.databaseForJQL()
const dbJQLcmd = dbJQL.command
const $ = dbJQL.command.aggregate
import $state from '../state/index.js';
import utils from '@/uni_modules/uni-im/sdk/utils/index.js';

export default class CloudData {
  dataList = []
  hasMore = true
  loading = false
  loadLimit = 100
  indexKey = '_id'
  __getMoreQueue = []
  // 被哪个类继承
  inheritedBy = ''
  constructor() {
    // this.dbJQL = dbJQL
    // this.dbJQLcmd = dbJQLcmd
    // this.dbJQL$ = $
    if(this.indexKey){
      this.dataMap = new Map()
    }
  }
  reset() {
    this.dataList.length = 0
    this.hasMore = true
    this.loading = false
    if(this.indexKey){
      this.dataMap.clear()
    }
  }
  remove(param) {
    let item = this.find(param)
    if(item){
      if(Array.isArray(this.dataList)){
        this.dataList.splice(this.dataList.indexOf(item), 1)
      }else{
        delete this.dataList[item._id]
      }
      if(this.indexKey){
        let key;
        this.indexKey.split('.').forEach(k => {
          key = key ? key[k] : item[k]
        })
        this.dataMap.delete(key)
      }
    }
    this.__afterRemove(item)
  }
  __beforeRemove(param) {
    // 空实现
    return param
  }
  __afterRemove(param) {
    // 空实现
    return param
  }
  __beforeFind(param) {
    // 空实现,用于子类重写
    return param
  }
  /**
   * @description 查找本地中存在的数据
   * @param {Object} param 查找条件,如果为空则返回全部数据,否则返回查找到的1条数据
   */
  find(param) {
    if(!param){
      throw new Error('请传入查找条件')
    }
    const dataList = this.dataList
    param = this.__beforeFind(param)
    let res;
    if(this.indexKey){
      // 先判断param是否和this.indexKey一样,可以走dataMap查找
      const indexKeyArr = this.indexKey.split('.');
      let mapKey = false;
      // 判断索引为字符串还是对象
      if(indexKeyArr.length == 1 && typeof param == 'string'){
        // 字符串索引
        mapKey = param
      }else if(typeof param == 'object' && convertObjToString(param) === this.indexKey){
        // 对象索引
        let key;
        indexKeyArr.forEach(k => {
          key = key ? key[k] : param[k]
        })
        mapKey = key
      }
      if (mapKey) {
        // console.time('find dataMap.get' + this.constructor.name)
        res = this.dataMap.get(mapKey)
        // console.timeEnd('find dataMap.get' + this.constructor.name)
      } else {
        console.log('注意:此次查找未走索引',param,this.indexKey,this.constructor.name)
      }
96
    } 
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
97
    
98 99 100 101 102 103 104 105 106 107
    if(!res) {
      console.time('find-no-index-' + this.constructor.name)
      // 默认查找条件为_id
      if(typeof param == 'string'){
        res = dataList.find(item => item._id == param)
      }else if(typeof param == 'object'){
        // console.log('param',param)
        res = dataList.find(item => isEq(item,param))
      }else{
        throw new Error('错误的查找条件')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
108
      }
109
      console.timeEnd('find-no-index-' + this.constructor.name)
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
110
    }
111 112 113 114
    if(this.__afterFind){
     res = this.__afterFind?.({param,res})
    }
    
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
    return res
  }
  /** @description 查询数据,先从本地查找,如果没有则从云端拉取
   * @param {Object} param 查找条件,如果为空则返回全部数据,否则返回查找到的1条数据
   */
  async get(param) {
    if(this.inheritedBy === 'conversation'){
      // debugger
    }
    if(!param){
      throw new Error('请传入查找条件')
    }
    let data = this.find(param)
    if(!data){
      data = await this.loadMore(param)
    }
    this.__afterGet(data)
    return data
  }
  __afterGet(param) {
    // 空实现,用于子类重写
    return param
  }
  count() {
    return this.dataList.length
  }
  __get(param){
    // 空实现,用于子类重写
    console.error('CloudData.pullData is not implemented')
    // 返回入参,避免报错
    return param
  }
  
  async getMore(param) {
    if(!param){
      if(!this.hasMore){
        console.log('没有更多数据了')
        return []
      }
      if (this.loading) {
        await new Promise((resolve, reject) => {
          console.warn('正在加载中,本次请求进入列队。模块名称:' + this.constructor.name)
          this.__getMoreQueue.push({resolve, reject})
        })
        console.log('列队任务已开始执行。模块名称:' + this.constructor.name)
      }else{
        this.loading = true
      }
    }
    let datas = []
    try{
      datas = await this.__get(param)
      if(!param){
        this.hasMore = datas.length === this.loadLimit
        this.loading = false
      }
    }catch(e){
      console.error('loadMore err',e)
      this.loading = false
      uni.showToast({
        title: e.message,
        icon: 'none'
      });
    }
    this.__afterGetMore?.(datas)
    // 执行下一个队列
    if(this.__getMoreQueue.length > 0){
      const item = this.__getMoreQueue.shift()
      item.resolve()
    }
    return datas
  }
  async loadMore(param) {
    // console.log('loadMore param',param);
    let datas = await this.getMore(param)
    if(datas.length > 0){
      datas = this.add(datas,{canSetIsFull:true})
    }
    return param == undefined ? datas : datas[0]
  }
  set(data){
    // 先判断是否存在
    let item = this.find(data.id || data._id || Object.keys(data)[0])
    if(item){
      // console.log('更新会话',data)
      try{
        utils.deepAssign(item,data)
      }catch(e){
        console.error('合并更新出错',{item,data,e})
      }
      return item
    }else{
      return this.add(data)
    }
  }
  __beforeAdd(param) {
    // 空实现,用于子类重写
    return param
  }
  add(param,options = {}) {
    console.time('add' + this.constructor.name)
    const {canUpdate = true,unshift = false} = options
    const paramIsArray = Array.isArray(param)
    let datas = paramIsArray ? param : [param]
    
    // console.time('add __beforeAdd' + this.constructor.name)
    let res = this.__beforeAdd(datas,options)
    // console.timeEnd('add __beforeAdd' + this.constructor.name)
    if(res !== undefined){
      datas = res
    }
    // 插入之前dataList是否为空
    const isEmpty = this.dataList.length === 0
    const resData = datas.map(item => {
      let val;
      if(this.indexKey){
        this.indexKey.split('.').forEach(k => {
          val = val ? val[k] : item[k]
        })
      }else{
        val = item._id || item.id || { [Object.keys(item)[0]]: item[Object.keys(item)[0]] }
      }
      // 如果当前数据列表为空或者没有传入索引值,则不检查要插入的数据是否存在
      let _data = (isEmpty || !val) ? false : this.find(val)
      // console.log('add _data',{_data,item})
      // 如果已经存在的,只更新不添加
      if(_data){
        if(canUpdate && item != _data){
          // console.log('添加的对象已经存在,更新对象',{item,item})
          try{
            utils.deepAssign(_data,item)
          }catch(e){
            console.error('合并更新出错',{item,_data,e})
          }
        }
        return _data
      }else{
        if(unshift){
          this.dataList.unshift(item)
          item = this.dataList.slice(0,1)[0]
        }else{
          this.dataList.push(item)
          item = this.dataList.slice(-1)[0]
        }
        if(this.indexKey){
          // console.time('dataMap set')
          let key;
          this.indexKey.split('.').forEach(k => {
            key = key ? key[k] : item[k]
          })
          const cs = this.__canSeaveToDataMap
          const val = cs ? cs(item) : true
          if(val){
            this.dataMap.set(key, item)
          }
          // console.log('this.dataMap',this.dataMap)
          // console.timeEnd('dataMap set')
        }
        return item
      }
    })
    this.__afterAdd(resData,options)
    // console.error('param',param)
    console.timeEnd('add' + this.constructor.name)
    return paramIsArray ? resData : resData[0]
  }
  __afterAdd(param) {
    // 空实现,用于子类重写
    return param
  }
  update(param, data) {
    let item = this.find(param)
    if(item){
      Object.assign(item, data)
    }
    return item
  }
}

function convertObjToString(obj) {
  let result = '';
  function recursiveConvert(currentObj, path) {
    for (const key in currentObj) {
      const value = currentObj[key];
      const newPath = path? `${path}.${key}` : key;
      if (typeof value === 'object') {
        recursiveConvert(value, newPath);
      } else {
        result += `${newPath}`;
      }
    }
  }
  recursiveConvert(obj, '');
  return result;
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
}

function isEq(a, b) {
  if (Array.isArray(a) || Array.isArray(b)) {
    console.error('不支持数组比较')
    return a === b;
  }
  let result = true;
  for (let key in b) {
    const valueA = a[key];
    const valueB = b[key];
    if (typeof valueB === 'object' 
      && valueB !== null
      && typeof valueA === 'object'
      && valueA !== null
    ) {
      return isEq(valueA, valueB);
    }
    result = valueA === valueB;
    if (!result) {
      break;
    }
  }
  return result;
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
333
}