Created
March 26, 2018 20:15
-
-
Save sramam/acfed3cca8e90731f3431643c894cc67 to your computer and use it in GitHub Desktop.
Maps oldData, newData and associated json-schema, to determine if update/recreate/no-op - not perfect, but a start
This file contains 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
import * as traverse from 'json-schema-traverse'; | |
import * as jsonFilter from 'json-schema-filter'; | |
import * as concordance from 'concordance'; | |
import * as _ from 'lodash'; | |
import * as jsonPtr from 'json-ptr'; | |
export enum Modification { | |
Update = 'Update', | |
Recreate = 'Recreate', | |
Noop = 'Noop' | |
} | |
/** | |
* Traverses `schema` with a sieve, and filters `data` with the sieved schema | |
* to yield a sub-data-object that is a perspective on the input. | |
* | |
* This could for-example be used to fetch all elements in `data` which have a | |
* default property defined. | |
* | |
* More interestingly, which utilize json-schema extensibility to detect which | |
* properties in data were specified to have say a `createOnly` property. | |
* | |
* This can be used to very easily compose whether a create-only property has | |
* been modified, allowing a quick 'update or delete-recreate' decision. | |
* | |
* Some care is taken to reconcile arrays which might have been re-ordered. | |
* This function focusses on correctness more than speed. | |
* | |
* Performance optimization is deffered till needed. | |
*/ | |
export const updateOrRecreate = (newData, oldData, schema, ignoreProps = <string[]>[]) => { | |
const sieve = (sch, prop) => { | |
const ignored = -1 < ignoreProps.indexOf(prop) | |
return (!ignored && sch.type === 'object' && sch.createOnly) | |
? sch : undefined; | |
} | |
// clone and pass both old & new data through the sieve. | |
const oldSieved = jsonSieve(_.merge({}, oldData), schema, sieve); | |
const newSieved = jsonSieve(_.merge({}, newData), schema, sieve); | |
// intersect the two sieved objects; | |
const intersection = concordance.diff(oldSieved, newSieved); | |
if (!!intersection) { | |
return Modification.Recreate; | |
} else { | |
return !!concordance.diff(oldData, newData) ? Modification.Update : Modification.Noop; | |
} | |
} | |
const jsonSieve = (data, schema, sieve) => { | |
const subSch = subSchema(schema, sieve); | |
return jsonFilter(subSch, data); | |
} | |
const subSchema = (schema, sieve) => { | |
let sub; | |
const collector = (sch, ptr, rootSch, prntPtr, prntKw, prntSch, prop) => { | |
const pass = sieve(sch, prop); // return undefined | |
const force = true; | |
if (pass !== undefined) { | |
// can add to sub | |
jsonPtr.set(sub, ptr, pass, force); | |
} | |
} | |
traverse(schema, collector); | |
return sub; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment