ltdtDiffByKey.mjs

import get from 'lodash-es/get.js'
import filter from 'lodash-es/filter.js'
import isestr from './isestr.mjs'
import isarr from './isarr.mjs'
import isbol from './isbol.mjs'
import haskey from './haskey.mjs'


/**
 * 比對新舊物件陣列,基於指定key為主鍵,比對vnew對vold中有差異之項目
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/ltdtDiffByKey.test.mjs Github}
 * @memberOf wsemi
 * @param {Array|Object} ltdtOld 輸入舊的物件陣列或物件
 * @param {Array|Object} ltdtNew 輸入新的物件陣列或物件
 * @param {String} key 輸入比對的主鍵key值字串
 * @param {Object} [opt={}] 輸入設定物件,預設{}
 * @param {Boolean} [opt.withInfor=true] 輸入是否提供infor資訊布林值,不提供可再加速,預設true
 * @returns {Object} 回傳比對結果物件
 * @example
 *
 * let ltdtOld = [{ id: 'id-1', a: 'a1' }, { id: 'id-2', a: 'a2' }, { id: 'id-3', a: 'a3' }]
 * let ltdtNew = [{ id: 'id-1', z: 'z3' }, { id: 'id-3', a: 'a3' }, { id: 'id-4', a: 'a4' }]
 * console.log(ltdtDiffByKey(ltdtOld, ltdtNew, 'id'))
 * // => {
 * //   del: [ { id: 'id-2', a: 'a2' } ],
 * //   add: [ { id: 'id-4', a: 'a4' } ],
 * //   same: [ { id: 'id-3', a: 'a3' } ],
 * //   diff: [ { id: 'id-1', z: 'z3' } ],
 * //   infor: { 'id-2': 'del', 'id-4': 'add', 'id-1': 'diff', 'id-3': 'same' }
 * // }
 *
 */
function ltdtDiffByKey(ltdtOld, ltdtNew, key, opt = {}) {

    // //def
    // let def = {
    //     infor: {},
    //     del: [],
    //     same: [],
    //     diff: [],
    //     add: [],
    // }

    //withInfor
    let withInfor = get(opt, 'withInfor')
    if (!isbol(withInfor)) {
        withInfor = true
    }

    //defult
    let r = {
        del: [],
        add: [],
        same: [],
        diff: [],
    }

    //check
    if (!isestr(key)) {
        console.log('invalid key')
        if (withInfor) {
            r.infor = {}
        }
        return r
    }

    //to array
    if (!isarr(ltdtOld)) { //有可能傳空陣列故使用isarr
        ltdtOld = [ltdtOld]
    }
    if (!isarr(ltdtNew)) { //有可能傳空陣列故使用isarr
        ltdtNew = [ltdtNew]
    }

    //filter
    ltdtOld = filter(ltdtOld, (v) => {
        return haskey(v, key)
    })
    ltdtNew = filter(ltdtNew, (v) => {
        return haskey(v, key)
    })

    //mapNew
    let mapNew = new Map(ltdtNew.map(item => [item[key], item]))

    //處理存在於ltdtOld中的項目
    for (let dtOld of ltdtOld) {
        let dtNew = mapNew.get(dtOld[key])
        if (!dtNew) {
            r.del.push(dtOld)
        }
        else {
            let isEqual = JSON.stringify(dtOld) === JSON.stringify(dtNew)
            if (isEqual) {
                r.same.push(dtNew)
            }
            else {
                r.diff.push(dtNew)
            }
            // 處理過的從 mapNew 移除,剩下的才是新增
            mapNew.delete(dtOld[key])
        }
    }

    //剩下的就是add
    r.add = Array.from(mapNew.values())

    //withInfor
    if (withInfor) {
        let infor = {}
        for (let v of r.del) {
            infor[v[key]] = 'del'
        }
        for (let v of r.add) {
            infor[v[key]] = 'add'
        }
        for (let v of r.diff) {
            infor[v[key]] = 'diff'
        }
        for (let v of r.same) {
            infor[v[key]] = 'same'
        }
        r.infor = infor
    }

    return r
}


export default ltdtDiffByKey