Skip to content

Instantly share code, notes, and snippets.

@sramam
Created March 26, 2018 20:15
Show Gist options
  • Save sramam/acfed3cca8e90731f3431643c894cc67 to your computer and use it in GitHub Desktop.
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
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