Last active
August 2, 2018 03:28
-
-
Save rjhilgefort/287c8654aecec162219073c260a1eb2d to your computer and use it in GitHub Desktop.
Check if objects are different, but only for white listed fields in a struct.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { log, clear } = console; | |
clear() | |
const trace = (tag) => (x) => { | |
log(`\n${tag}\n==================================================`); | |
log(JSON.stringify(x, 0, 2)); | |
return x; | |
} | |
// misc.js | |
/////////////////////////////////////////////////////////////////////////////////////// | |
const isNotNil = R.complement(R.isNil); | |
const notHas = R.complement(R.has); | |
const isObject = R.compose(R.equals('Object'), R.type); | |
const notObject = R.complement(isObject); | |
const isArray = R.compose(R.equals('Array'), R.type); | |
const allAreObjects = R.compose(R.all(isObject), R.values); | |
// obj-diff.js | |
/////////////////////////////////////////////////////////////////////////////////////// | |
const hasLeft = R.has('left'); | |
const hasRight = R.has('right'); | |
const hasBoth = R.both(hasLeft, hasRight); | |
const isEqual = R.both(hasBoth, R.compose(R.apply(R.equals), R.values)); | |
const markAdded = R.compose(R.append(undefined), R.values); | |
const markRemoved = R.compose(R.prepend(undefined), R.values); | |
const isAddition = R.both(hasLeft, R.complement(hasRight)); | |
const isRemoval = R.both(R.complement(hasLeft), hasRight); | |
// ObjDiffResult :: { [String]: Array<Any, Any> | ObjDiffResult } | |
// ObjDiff :: Object -> Object -> ObjDiffResult | |
const objDiff = R.curry((left, right) => R.compose( | |
R.map(R.cond([ | |
[isAddition, markAdded], | |
[isRemoval, markRemoved], | |
[hasBoth, R.ifElse( | |
allAreObjects, | |
R.compose(R.apply(objDiff), R.values), | |
R.values | |
)] | |
])), | |
R.reject(isEqual), | |
R.useWith( | |
R.mergeWith(R.merge), | |
[R.map(R.objOf('left')), R.map(R.objOf('right'))] | |
), | |
)(left, right)); | |
// is-obj-diff.js | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// Prop :: String | |
// StructPath :: { [String]: Array<Prop> | StructPath } | |
// ExpandedStructPath :: { [String]: true | ExpandedStructPath } | |
// Spec :: StructPath | Array<Prop> | Prop | Null | |
// ExpandStructPath :: Spec -> ExpandedStructPath | |
const expandStructPath = spec => | |
R.cond([ | |
[R.is(String), R.compose(expandStructPath, R.of)], | |
[isObject, R.map(expandStructPath)], | |
[isArray, R.converge(R.zipObj, [R.identity, R.identity])], | |
[R.T, R.identity] | |
])(spec); | |
const _objDiffWhitelistFilter = R.curry((whiteList, diffRes) => R.compose( | |
R.reduce( | |
(acc, [key, diffResValue]) => { | |
const whiteListValue = R.path([key], whiteList); | |
// `null` `whiteList` indicates any diff is valid | |
// Skip any indexes that don't exist in the whiteList | |
if (isNotNil(whiteList) && isNil(whiteListValue)) return acc; | |
// if: `diffResValue` is an array, indicates a valid difference | |
// or: `whiteListValue` as a non object indicates it isn't spec'd as a substructure | |
// and there's no need to recurse any deeper. | |
if (isArray(diffResValue) || notObject(whiteListValue)) return R.reduced(true); | |
// Dig furtther down into the structure | |
return _objDiffWhitelistFilter(whiteListValue, diffResValue); | |
}, | |
false, | |
), | |
R.toPairs, | |
)(diffRes)); | |
// ObjDiffWhitelistFilter :: Spec -> ObjDiffResult -> Boolean | |
const objDiffWhitelistFilter = curry((whiteListStruct, objDiffRes) => R.compose( | |
_objDiffWhitelistFilter(R.__, objDiffRes), | |
expandStructPath, | |
)(whiteListStruct)); | |
// NOTES: | |
// - When `WhiteListStruct` is `Nil`, assume all fields should be checked | |
// isObjDiff :: Spec -> Object -> Object -> Boolean | |
const isObjDiff = R.curry((whiteListStruct, left, right) => R.compose( | |
objDiffWhitelistFilter(whiteListStruct), | |
objDiff, | |
)(left, right)); | |
// index.js | |
/////////////////////////////////////////////////////////////////////////////////////// | |
const objectOne = { | |
foo: { | |
variantInfo: { | |
product: 'ONEAPP_SAMTV', | |
somethingExtra: 'hi mom', | |
featureOverrides: [ | |
{ name: 'bug', type: 'STRING', value: 'feature' }, | |
{ name: 'extra', type: 'STRING', value: 'feature' }, | |
], | |
jsonForOverrides: 'A', | |
useJsonForOverrides: false, | |
} | |
} | |
} | |
const objectTwo = { | |
foo: { | |
variantInfo: { | |
product: 'ONEAPP_SAMTV', | |
featureOverrides: [ | |
{ name: 'bug', type: 'STRING', value: 'feature' } | |
], | |
jsonForOverrides: '', | |
useJsonForOverrides: false | |
} | |
} | |
} | |
isObjDiff( | |
// TRUE | |
{ foo: { variantInfo: ['product', 'featureOverrides', 'jsonForOverrides', 'useJsonForOverrides'] } }, | |
// FALSE | |
//{ foo: { variantInfo: ['product'] } }, | |
// TRUE | |
// ['foo'], | |
// TRUE | |
// 'foo', | |
// TRUE | |
//null, | |
objectOne, | |
objectTwo | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment