|
@@ -0,0 +1,88 @@
|
|
|
+import { transform, isEqual, isObject, get } from 'lodash'
|
|
|
+
|
|
|
+type Dict = {
|
|
|
+ [key: string]: boolean | Dict
|
|
|
+}
|
|
|
+
|
|
|
+export function diff(newObject: any = {}, oldObject: any = {}, ignore?: Dict) {
|
|
|
+ const currentIgnoreList = ignore
|
|
|
+ ? Object.entries(ignore).reduce(
|
|
|
+ (accumulator, [key, value]) =>
|
|
|
+ typeof value === 'boolean' ? [...accumulator, key] : accumulator,
|
|
|
+ [] as string[]
|
|
|
+ )
|
|
|
+ : []
|
|
|
+ const transformResult = transform(newObject, (result: any, value: any, key: string) => {
|
|
|
+ if (!currentIgnoreList.includes(key) && !isEqual(value, oldObject[key])) {
|
|
|
+ const child = ignore && ignore[key]
|
|
|
+ let childIgnoreList
|
|
|
+ if (result instanceof Array) {
|
|
|
+ childIgnoreList = ignore
|
|
|
+ } else if (typeof child !== 'boolean') {
|
|
|
+ childIgnoreList = child
|
|
|
+ } else {
|
|
|
+ childIgnoreList = undefined
|
|
|
+ }
|
|
|
+ const newValue =
|
|
|
+ isObject(value) && isObject(oldObject[key])
|
|
|
+ ? diff(value, oldObject[key], childIgnoreList)
|
|
|
+ : value
|
|
|
+ if (typeof newValue === 'boolean' || !!newValue) result[key] = newValue
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return Object.keys(transformResult).length > 0 ? transformResult : undefined
|
|
|
+}
|
|
|
+
|
|
|
+export function deepDiff(newObject: any = {}, oldObject: any = {}, ignore?: Dict) {
|
|
|
+ return {
|
|
|
+ added: diff(newObject, oldObject, ignore),
|
|
|
+ removed: diff(oldObject, newObject, ignore),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+interface IcompareOptions<T> {
|
|
|
+ compareKeys: (keyof T)[]
|
|
|
+ diffIgnore?: Dict
|
|
|
+ keyNames?: {
|
|
|
+ inA: string
|
|
|
+ inB: string
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export function compare<T>(objectsA: T[], objectsB: T[], compareOptions: IcompareOptions<T>) {
|
|
|
+ const { keyNames, diffIgnore, compareKeys } = compareOptions
|
|
|
+ const { inA, inB } = keyNames || { inA: 'inFile', inB: 'inDb' }
|
|
|
+ let copyB = [...objectsB]
|
|
|
+ let copyA: T[] = []
|
|
|
+ for (let objectA of objectsA) {
|
|
|
+ const idxObjectB = copyB.findIndex(objectB =>
|
|
|
+ compareKeys.reduce((accumulator, value) => {
|
|
|
+ console.log(get)
|
|
|
+ return accumulator && get(objectA, value, 1) === get(objectB, value, 2)
|
|
|
+ }, true as boolean)
|
|
|
+ )
|
|
|
+ const objectB = copyB[idxObjectB]
|
|
|
+ copyB = [...copyB.slice(0, idxObjectB), ...copyB.slice(idxObjectB + 1)]
|
|
|
+ copyA = [
|
|
|
+ ...copyA,
|
|
|
+ {
|
|
|
+ ...objectA,
|
|
|
+ changes: deepDiff(objectA, objectB, diffIgnore),
|
|
|
+ [inA]: true,
|
|
|
+ [inB]: !!objectB,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ for (let objectB of copyB) {
|
|
|
+ copyA = [
|
|
|
+ ...copyA,
|
|
|
+ {
|
|
|
+ ...objectB,
|
|
|
+ changes: deepDiff(undefined, objectB, diffIgnore),
|
|
|
+ [inA]: false,
|
|
|
+ [inB]: true,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ return copyA
|
|
|
+}
|