diff --git a/__tests__/object/index.test.ts b/__tests__/object/index.test.ts index f74bcd4..e4dbf29 100644 --- a/__tests__/object/index.test.ts +++ b/__tests__/object/index.test.ts @@ -1,4 +1,4 @@ -import { isObject, objToStr, isObjEqual, hasOwnProperty, compareJsonDiff } from '../../src/object' +import { isObject, objToStr, isObjEqual, hasOwnProperty, compareJsonDiff, mergeObjectChanges } from '../../src/object' const objectA = { name: 'adapcon', @@ -124,3 +124,245 @@ describe('isObjEqual', () => { expect(isObjEqual(null, null)).toEqual(true) }) }) + +describe('Merge Objects Changes tests', () => { + describe('Merge Objects Changes tests without custom params', () => { + it('should merge two objects', () => { + const obj1 = { a: 1, b: 2 } + const obj2 = { a: 1, b: 4 } + const result = mergeObjectChanges(obj1, obj2) + expect(result).toStrictEqual({ a: 1, b: 4 }) + }) + + it('should merge two objects with nested objects', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } + const obj2 = { a: 1, b: { c: 4, d: 3 } } + const result = mergeObjectChanges(obj1, obj2) + expect(result).toStrictEqual({ a: 1, b: { c: 4, d: 3 } }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } as T + const obj2 = { a: 1, b: undefined } as T + const result = mergeObjectChanges(obj1, obj2) + expect(result).toStrictEqual({ a: 1 }) + }) + + it('should merge two objects with nested objects and arrays', () => { + const obj1 = { a: 1, b: { c: 2, d: [1, 2] } } + const obj2 = { a: 1, b: { c: 4, d: [1, 3] } } + const result = mergeObjectChanges(obj1, obj2) + expect(result).toStrictEqual({ a: 1, b: { c: 4, d: [1, 3] } }) + }) + + it('should merge two objects with undefined values with not present on new object without options param', () => { + const obj1 = { a: 1, b: 2 } + const obj2 = { a: 1 } + const result = mergeObjectChanges(obj1, obj2) + expect(result).toStrictEqual({ a: 1 }) + }) + }) + + describe('Merge Objects Changes tests without custom params', () => { + it('should merge two objects with same type but diff keys and same values on keys that are in both', () => { + const obj1 = { a: 1, b: 2 } as T + const obj2 = { a: 1, c: 3 } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true + }) + expect(result).toStrictEqual({ a: 1, b: 2, c: 3 }) + }) + + it('should merge two objects with same type but diff keys and diff values on keys that are in both', () => { + const obj1 = { a: 1, b: 2 } as T + const obj2 = { a: 2, c: 3 } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true + }) + expect(result).toStrictEqual({ a: 2, b: 2, c: 3 }) + }) + }) + + describe('Merge Objects Changes tests with useOldKeysIfNotPresentInNew custom params', () => { + it('should merge two objects with new values if key is present on newObj and not on oldObj with useOldKeysIfNotPresentInNew param as true', () => { + const obj1 = { a: 1, b: 2 } + const obj2 = { a: 2 } + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true + }) + expect(result).toStrictEqual({ a: 2, b: 2 }) + }) + + it('should merge two objects with new values if key is present on newObj and not on oldObj - useOldKeysIfNotPresentInNew set as false', () => { + const obj1 = { a: 1 } + const obj2 = { a: 2, b: 2 } + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: false + }) + expect(result).toStrictEqual({ a: 2, b: 2 }) + }) + + it('should merge two objects with undefined values with not present on new object - useOldKeysIfNotPresentInNew param not set', () => { + const obj1 = { a: 1, b: 2 } + const obj2 = { a: 2 } + const result = mergeObjectChanges(obj1, obj2) + expect(result).toStrictEqual({ a: 2 }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } as T + const obj2 = { a: 1, b: undefined } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true + }) + expect(result).toStrictEqual({ a: 1, b: { c: 2, d: 3 } }) + }) + }) + + describe('Merge Objects Changes tests with addNewKeys param', () => { + it('should add new values with addNewKeys as true', () => { + const obj1 = { a: 1 } + const obj2 = { a: 1, b: 2 } + const result = mergeObjectChanges(obj1, obj2, { + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 1, b: 2 }) + }) + + it('should not merge new values with addNewKeys params as false', () => { + const obj1 = { a: 1 } + const obj2 = { a: 1, b: 2 } + const result = mergeObjectChanges(obj1, obj2, { + addNewKeys: false + }) + expect(result).toStrictEqual({ a: 1 }) + }) + + it('should add new values when addNewKeys is not set (default value is true)', () => { + const obj1 = { a: 1 } + const obj2 = { a: 1, b: 2 } + const result = mergeObjectChanges(obj1, obj2) + expect(result).toStrictEqual({ a: 1, b: 2 }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: undefined } as T + const obj2 = { a: 1, b: { c: 2, d: 3 } } as T + const result = mergeObjectChanges(obj1, obj2, { + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 1, b: { c: 2, d: 3 } }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: undefined } as T + const obj2 = { a: 1, b: { c: 2, d: 3 } } as T + const result = mergeObjectChanges(obj1, obj2, { + addNewKeys: false + }) + expect(result).toStrictEqual({ a: 1 }) + }) + }) + + describe('Merge Objects Changes tests with both useOldKeysIfNotPresentInNew and addNewKeys params', () => { + it('should merge two objects with new values if key is present on newObj and not on oldObj with useOldKeysIfNotPresentInNew param as true and addNewKeys as true', () => { + const obj1 = { a: 1, b: 2 } + const obj2 = { a: 2 } + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true, + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 2, b: 2 }) + }) + }) + + it('should merge two objects with new values if key is present on newObj and not on oldObj with useOldKeysIfNotPresentInNew param as true and addNewKeys as false', () => { + const obj1 = { a: 1, b: 2 } + const obj2 = { a: 2 } + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true, + addNewKeys: false + }) + expect(result).toStrictEqual({ a: 2, b: 2 }) + }) + + it('should merge two objects with new values if key is present on newObj and not on oldObj with useOldKeysIfNotPresentInNew param as false and addNewKeys as true', () => { + const obj1 = { a: 'um' } + const obj2 = { a: 'dois', b: 2 } + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: false, + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 'dois', b: 2 }) + }) + + it('should merge two objects with new values if key is present on newObj and not on oldObj with useOldKeysIfNotPresentInNew param as false and addNewKeys as false', () => { + const obj1 = { a: 1 } + const obj2 = { a: 1, b: 2 } + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: false, + addNewKeys: false + }) + expect(result).toStrictEqual({ a: 1 }) + }) + + it('should merge objects with keys present singly in new and old but not in both with useOldKeysIfNotPresentInNew and addNewKeys params ', () => { + const obj1 = { a: 1, b: 2 } as T + const obj2 = { a: 1, c: 2 } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true, + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 1, b: 2, c: 2 }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } as T + const obj2 = { a: 1, b: undefined, e: 4 } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true, + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 1, b: { c: 2, d: 3 }, e: 4 }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } as T + const obj2 = { a: 1, b: undefined } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: true, + addNewKeys: false + }) + expect(result).toStrictEqual({ a: 1, b: { c: 2, d: 3 } }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } as T + const obj2 = { a: 1, b: undefined, e: 5 } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: false, + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 1, e: 5 }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } as T + const obj2 = { a: 1, b: undefined, e: 4 } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: false, + addNewKeys: false + }) + expect(result).toStrictEqual({ a: 1 }) + }) + + it('should merge two objects with nested objects on old and undefined on new', () => { + const obj1 = { a: 1, b: { c: 2, d: 3 } } as T + const obj2 = { a: 1, b: undefined, e: 4 } as T + const result = mergeObjectChanges(obj1, obj2, { + useOldKeysIfNotPresentInNew: false, + addNewKeys: true + }) + expect(result).toStrictEqual({ a: 1, e: 4 }) + }) +}) diff --git a/src/object/index.ts b/src/object/index.ts index 9f52ea5..d7a0b4e 100644 --- a/src/object/index.ts +++ b/src/object/index.ts @@ -46,3 +46,65 @@ export const compareJsonDiff = ({ baseObject, compareObject }: { baseObject: obj return { diff, removed } } + +type MergeObjectChangesOptions = { + useOldKeysIfNotPresentInNew?: boolean + addNewKeys?: boolean +} +export function mergeObjectChanges ( + oldObj: T, + newObj: T, + options: MergeObjectChangesOptions = { + useOldKeysIfNotPresentInNew: false, + addNewKeys: true + } +): T { + options.useOldKeysIfNotPresentInNew = options.useOldKeysIfNotPresentInNew ?? false + options.addNewKeys = options.addNewKeys ?? true + + const result = {} as T + + function checkKeys (obj: T) { + for (const key in obj) { + if (Array.isArray(oldObj[key]) && Array.isArray(newObj[key])) { + result[key] = newObj[key] + } else if (typeof oldObj[key] === 'object' && typeof newObj[key] === 'object') { + result[key] = mergeObjectChanges(oldObj[key], newObj[key]) + continue + } + + if ( + // has key with value on old but not on new + (newObj[key] === undefined || newObj[key] === null) && + (oldObj[key] !== undefined && oldObj[key] !== null) && + options.useOldKeysIfNotPresentInNew + ) { + result[key] = oldObj[key] + continue + } else if ( + // has key with value on new but not on old + (newObj[key] !== undefined && newObj[key] !== null) && + (oldObj[key] === undefined || oldObj[key] === null) && + options.addNewKeys + ) { + result[key] = newObj[key] + continue + } else if ( + // has key with value on both + (newObj[key] !== undefined && newObj[key] !== null) && + (oldObj[key] !== undefined && oldObj[key] !== null) + ) { + if (oldObj[key] !== newObj[key]) { + result[key] = newObj[key] + } else { + result[key] = oldObj[key] + } + } + } + } + + checkKeys(oldObj) + checkKeys(newObj) + + return result +} diff --git a/src/string/encrypt.ts b/src/string/encrypt.ts index 0474392..892a729 100644 --- a/src/string/encrypt.ts +++ b/src/string/encrypt.ts @@ -1,7 +1,7 @@ import crypto from 'crypto' import { InternalError } from '..' -export function encryptPassword(passwordToEncrypt: string, encryptionKey: string): string { +export function encryptPassword (passwordToEncrypt: string, encryptionKey: string): string { const salt = crypto.randomBytes(16).toString('hex') const key = crypto.scryptSync(encryptionKey, salt, 24) const iv = Buffer.alloc(16, 0) @@ -11,7 +11,7 @@ export function encryptPassword(passwordToEncrypt: string, encryptionKey: string return `${salt}:${encryptedPassword}` } -export function decryptPassword(storedPassword: string, encryptionKey: string): string { +export function decryptPassword (storedPassword: string, encryptionKey: string): string { try { const [salt, encryptedPassword] = storedPassword.split(':') const key = crypto.scryptSync(encryptionKey, salt, 24)