UNPKG

@data-client/normalizr

Version:

Normalizes and denormalizes JSON according to schema for Redux and Flux applications

2 lines (1 loc) 10.5 kB
class e{constructor(){this.localCache=new Map}getEntity(e,t,n,i){const s=t.key;this.localCache.has(s)||this.localCache.set(s,new Map);const r=this.localCache.get(s);return r.get(e)||i(r),r.get(e)}getResults(e,t,n){return{data:n(),paths:[]}}}const t=Symbol("INVALID"),n={};function i(e){return null!==e&&void 0!==e.pk}const s=e=>{if("production"!==process.env.NODE_ENV){if(Array.isArray(e)&&e.length>1)throw new Error(`Expected schema definition to be a single schema, but found ${e.length}.`)}return e[0]},r=e=>void 0!==e&&"symbol"!=typeof e,o=(e,t,n,i,r,o)=>{e=s(e);const c=(e=>Array.isArray(e)?e:Object.keys(e).map((t=>e[t])))(t);return c.map((t=>o(e,t,n,i,r)))},c=(e,t,n,i)=>(e=s(e),t.map?t.map((t=>i(e,t))).filter(r):t);function a(){}function h(){return h=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var i in n)({}).hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},h.apply(null,arguments)}const u=(e,t,n,i,s,r)=>{const o=h({},t),c=Object.keys(e);for(let n=0;n<c.length;n++){const i=c[n],a=r(e[i],t[i],t,i,s);void 0===a?delete o[i]:o[i]=a}return o},l=(e,n,i,s)=>{if(function(e){return!("function"!=typeof e.hasOwnProperty||!(Object.hasOwnProperty.call(e,"__ownerID")||e._map&&Object.hasOwnProperty.call(e._map,"__ownerID")))}(n))return function(e,n,i,s){let r=!1;const o=Object.keys(e).reduce(((t,n)=>{const i=`${n}`,o=s(e[i],t.get(i));return"symbol"==typeof o&&(r=!0),t.has(i)?t.set(i,o):t}),n);return r?t:o}(e,n,0,s);const r=h({},n);let o=!1;const c=Object.keys(e);for(let t=0;t<c.length;t++){const n=c[t],i=s(e[n],r[n]);void 0!==r[n]&&(r[n]=i),"symbol"==typeof i&&(o=!0)}return o?t:r};function y(e,t,n,i){const s={};for(const r of Object.keys(e))s[r]=n(e[r],t,i);return s}const d=(e,t,i,s)=>function(r,o){const c="object"!=typeof o,a=c?e({key:r.key,pk:o}):o;if("symbol"==typeof a)return r.denormalize(a,i,s);if(void 0===a&&c&&""!==o&&"undefined"!==o)return t.getEntity(o,r,n,(e=>{e.set(o,void 0)}));if("object"!=typeof a||null===a)return a;let h=c?o:r.pk(a,void 0,void 0,i);return void 0===h||""===h||"undefined"===h?function(e){const t=new Map;return e(t),t.get("")}((e=>p(r,a,"",e,i,s))):("string"!=typeof h&&(h=`${h}`),t.getEntity(h,r,a,(e=>p(r,a,h,e,i,s))))};function p(e,n,i,s,r,o){const c=e.createIfValid(n);void 0===c?s.set(i,t):(s.set(i,c),s.set(i,e.denormalize(c,r,o)))}const f=(e,t,n)=>{const s=d(e,t,n,r);function r(e,t){if(!e)return t;if(null==t)return t;if("function"==typeof e.denormalize)return i(e)?s(e,t):e.denormalize(t,n,r);if("function"==typeof e)return e(t);if("object"==typeof e){return(Array.isArray(e)?c:l)(e,t,n,r)}return t}return(e,n)=>{const i=Object(n)===n&&Object(e)===e;return t.getResults(n,i,(()=>r(e,n)))}};class g{constructor({entities:e,indexes:t}){this.entities=e,this.indexes=t}tracked(e){const n=this,i=[{path:[""],entity:e}];return[{INVALID:t,getIndex(...e){const t=n.getIndex(...e);return i.push({path:e,entity:t}),n.getIndexEnd(t,e[2])},getEntity(...e){const t=n.getEntity(...e);return i.push({path:e,entity:t}),t},getEntities(e){const t=n.getEntitiesObject(e);return i.push({path:[e],entity:t}),n.getEntities(e)}},i]}}class v extends g{constructor(e){super(e)}getEntitiesObject(e){return this.entities[e]}getEntities(e){const t=this.entities[e];if(void 0!==t)return{keys:()=>Object.keys(t),entries:()=>Object.entries(t)}}getEntity(e,t){var n;return null==(n=this.entities[e])?void 0:n[t]}getIndex(e,t){var n;return null==(n=this.indexes[e])?void 0:n[t]}getIndexEnd(e,t){return null==e?void 0:e[t]}}const w={QueryDelegate:v,getEntities:e=>({key:t,pk:n})=>{var i;return null==(i=e[t])?void 0:i[n]}};function x(t,n,i,s=[]){return void 0===t||void 0===n?n:f(w.getEntities(i),new e,s)(t,n).data}class E{constructor(){this.next=new WeakMap,this.nextPath=void 0}get(e,t){let i=this.next.get(e);if(!i)return m;for(;i.nextPath;){var s;const e=null!=(s=t(i.nextPath))?s:n;if(i=i.next.get(e),!i)return m}return[i.value,i.journey]}set(e,t){if(e.length<1)throw new k;let i=this;for(const{path:t,entity:s}of e){let e=i.next.get(s);e||(e=new b,i.next.set(null!=s?s:n,e)),i.nextPath=t,i=e}i.nextPath=void 0,i.value=t,i.journey=e.map((e=>e.path))}}const m=[void 0,void 0];class b{constructor(){this.next=new WeakMap,this.nextPath=void 0,this.value=void 0,this.journey=[]}}class k extends Error{constructor(...e){super(...e),this.message="Keys must include at least one member"}}class M extends v{constructor(e,t){super(e),this.newEntities=new Map,this.newIndexes=new Map,this.entitiesMeta=e.entitiesMeta,this.meta=t,this.checkLoop=function(){const e=new Map;return function(t,n,i){let s=e.get(t);s||(s=new Map,e.set(t,s));let r=s.get(n);return r||(r=new Set,s.set(n,r)),!!r.has(i)||(r.add(i),!1)}}()}getNewEntity(e,t){return this.getNewEntities(e).get(t)}getNewEntities(e){return this.newEntities.has(e)||(this.newEntities.set(e,new Map),this.entities[e]=h({},this.entities[e]),this.entitiesMeta[e]=h({},this.entitiesMeta[e])),this.newEntities.get(e)}getNewIndexes(e){return this.newIndexes.has(e)||(this.newIndexes.set(e,new Map),this.indexes[e]=h({},this.indexes[e])),this.newIndexes.get(e)}mergeEntity(e,t,n){const i=e.key;let s=n,r=this.meta,o=this.getNewEntity(i,t);if(o)s=e.merge(o,n);else if(o=this.getEntity(i,t),o){const c=this.getMeta(i,t);s=e.mergeWithStore(c,r,o,n),r=e.mergeMetaWithStore(c,r,o,n)}this.setEntity(e,t,s,r)}setEntity(e,n,i,s=this.meta){const r=e.key,o=this.getNewEntities(r),c=!o.has(n);o.set(n,i),e.indexes&&function(e,n,i,s,r,o){for(const c of n){i.has(c)||i.set(c,s[c]={});const n=i.get(c);o[e]&&delete n[o[e][c]],o&&o[e]&&o[e][c]!==r[c]&&(n[o[e][c]]=t),c in r?n[r[c]]=e:"production"!==process.env.NODE_ENV&&console.warn(`Index not found in entity. Indexes must be top-level members of your entity.\nIndex: ${c}\nEntity: ${JSON.stringify(r,void 0,2)}`)}}(n,e.indexes,this.getNewIndexes(r),this.indexes[r],i,this.entities[r]),this._setEntity(r,n,i),c&&this._setMeta(r,n,s)}invalidate({key:e},n){this.setEntity({key:e},n,t)}_setEntity(e,t,n){this.entities[e][t]=n}_setMeta(e,t,n){this.entitiesMeta[e][t]=n}getMeta(e,t){return this.entitiesMeta[e][t]}}const I=(e,t,n=[],{entities:i,indexes:s,entitiesMeta:r}=j,c={fetchedAt:0,date:Date.now(),expiresAt:1/0})=>{if(null==e)return{result:t,entities:i,indexes:s,entitiesMeta:r};const a=function(e){return["object","function"].includes(typeof e)?"object":typeof e}(e);if(null===t||typeof t!==a&&(void 0===e.key||void 0!==e.pk||"string"!=typeof t)){if("production"!==process.env.NODE_ENV){const n=e=>{try{return"string"!=typeof JSON.parse(e)}catch(e){return!1}};throw"string"==typeof t&&n(t)?new Error(`Normalizing a string, but this does match schema.\n\nParsing this input string as JSON worked. This likely indicates fetch function did not parse\nthe JSON. By default, this only happens if "content-type" header includes "json".\nSee https://dataclient.io/rest/api/RestEndpoint#parseResponse for more information\n\n Schema: ${JSON.stringify(e,void 0,2)}\n Input: "${t}"`):new Error(`Unexpected input given to normalize. Expected type to be "${a}", found "${null===t?"null":typeof t}".\n\n Schema: ${JSON.stringify(e,void 0,2)}\n Input: "${t}"`)}throw new Error(`Unexpected input given to normalize. Expected type to be "${a}", found "${null===t?"null":typeof t}".`)}const l={result:"",entities:h({},i),indexes:h({},s),entitiesMeta:h({},r)},y=(e=>{const t=(n,i,s,r,c)=>i&&n?n.normalize&&"function"==typeof n.normalize?"object"!=typeof i?n.pk?`${i}`:i:n.normalize(i,s,r,c,t,e):"object"!=typeof i||"object"!=typeof n?i:(Array.isArray(n)?o:u)(n,i,s,r,c,t):i;return t})(new M(l,c));return l.result=y(e,t,t,void 0,n),l};const j={entities:{},indexes:{},entitiesMeta:{}};class O{constructor(e,t,n){this.dependencies=[],this.cycleCache=new Map,this.cycleIndex=-1,this.localCache=new Map,this._getEntity=e,this._getCache=t,this._resultCache=n}getEntity(e,t,n,i){const s=t.key,{localCacheKey:r,cycleCacheKey:o}=this.getCacheKey(s);if(r.get(e))o.has(e)?this.cycleIndex=o.get(e):this.dependencies.push({path:{key:s,pk:e},entity:n});else{const c=this._getCache(e,t),[a,h]=c.get(n,this._getEntity);if(h)return r.set(e,a.value),this.dependencies.push(...a.dependencies),a.value;{const t=this.dependencies.length;o.set(e,t),this.dependencies.push({path:{key:s,pk:e},entity:n}),i(r),o.delete(e);const a=this.dependencies.slice(-1===this.cycleIndex?t:this.cycleIndex),h={dependencies:a,value:r.get(e)};c.set(a,h),this.cycleIndex===t&&(this.cycleIndex=-1)}}return r.get(e)}getCacheKey(e){this.localCache.has(e)||this.localCache.set(e,new Map),this.cycleCache.has(e)||this.cycleCache.set(e,new Map);return{localCacheKey:this.localCache.get(e),cycleCacheKey:this.cycleCache.get(e)}}getResults(e,t,n){if(!t)return{data:n(),paths:this.paths()};let[i,s]=this._resultCache.get(e,this._getEntity);return void 0===s?(i=n(),s=this.paths(),this.dependencies.unshift({path:{key:"",pk:""},entity:e}),this._resultCache.set(this.dependencies,i)):s.shift(),{data:i,paths:s}}paths(){return this.dependencies.map((e=>e.path))}}function C(e){return void 0!==e&&(!(e&&"object"==typeof e&&!Array.isArray(e))||Object.values(e).every(C))}class N{constructor(e=w){var t;this.endpoints=new E,this.queryKeys=new Map,this.policy=e,this._getCache=(t=new Map,(e,n)=>{var i;const s=n.key,r=null!=(i=n.cacheWith)?i:n;t.has(s)||t.set(s,new Map);const o=t.get(s);o.has(e)||o.set(e,new WeakMap);const c=o.get(e);let a=c.get(r);return a||(a=new E,c.set(r,a)),a})}denormalize(e,t,n,i=[]){if(void 0===e)return{data:t,paths:[]};if(void 0===t)return{data:void 0,paths:[]};const s=this.policy.getEntities(n);return f(s,new O(s,this._getCache,this.endpoints),i)(e,t)}query(e,t,n,i=JSON.stringify(t)){const s=this.buildQueryKey(e,t,n,i);return s?this.denormalize(e,s,n.entities,t):{data:void 0,paths:[]}}buildQueryKey(e,t,n,i=JSON.stringify(t)){if("object"!=typeof e&&"function"!=typeof e.queryKey||!e)return e;let s=this.queryKeys.get(i);s||(s=new E,this.queryKeys.set(i,s));const r=new this.policy.QueryDelegate(n);let[o,c]=s.get(e,(h=r,e=>h[["","getEntitiesObject","getEntity","getIndex"][e.length]](...e)));var h;if(!c){const[n,i]=r.tracked(e);o=function(e){return function t(n,i){return function(e){return!!e&&"function"==typeof e.queryKey}(n)?n.queryKey(i,t,e):"object"==typeof n&&n?(Array.isArray(n)?a:y)(n,i,t,e):n}}(n)(e,t),s.set(i,o)}return o}}var _={Invalid:1,InvalidIfStale:2,Valid:3};export{g as BaseDelegate,_ as ExpiryStatus,t as INVALID,N as MemoCache,w as MemoPolicy,E as WeakDependencyMap,x as denormalize,i as isEntity,I as normalize,C as validateQueryKey};