All files / module/resource ResourceBuilder.js

78.57% Statements 22/28
66.67% Branches 8/12
50% Functions 4/8
77.78% Lines 21/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105                          6x                         11x   11x 11x 11x   11x   11x 2x     11x                   2x   2x 6x 4x   4x       4x 4x   4x 2x     4x       6x     6x                                                                
import { hasRelationship } from './hasRelationship'
import { hasLoadableRelationship } from './hasLoadableRelationship'
import { hasLoadedRelationship } from './hasLoadedRelationship'
import { listRelationship } from './listRelationship'
import { loadRelationship } from './loadRelationship'
import { getRelationship } from './getRelationship'
import { deref, hasOwn } from '../../shared/utils'
 
/**
 * @class ResourceBuilder
 */
export class ResourceBuilder {
  constructor (store) {
    this.store = store
  }
 
  /**
  * Returns a new functional resource object
  *
  * Functional resource objects are structurally identical to
  * normal JSON:API resource objects but are enhanced with
  * methods to simplify access to relationships.
  *
  * @param {Object} jsonResourceObject
  */
  build (jsonResourceObject) {
    const obj = deref(jsonResourceObject.data) // why tho?
 
    obj.hasRelationship = hasRelationship(obj)
    obj.hasLoadableRelationship = hasLoadableRelationship(obj)
    obj.hasLoadedRelationship = hasLoadedRelationship(obj)
 
    obj.get = (attributeName) => hasOwn(obj.attributes, attributeName) ? obj.attributes[attributeName] : new Error(`attribute "${attributeName}" not found`)
 
    if (hasOwn(obj, 'relationships')) {
      this.buildRelationshipMethods(obj)
    }
 
    return obj
  }
 
  /**
   * Adds Methods (get, load, list) to the relationships for getting / loading them
   * Adds Shorthand Methods (rel / loadRel)
   *
   * @param {Object} jsonResourceObject
   */
  buildRelationshipMethods (obj) {
    const relationships = obj.relationships
 
    for (const currentRelationshipName in relationships) {
      if (obj.hasRelationship(currentRelationshipName)) {
        const relatedObject = relationships[currentRelationshipName]
 
        const relationshipConfig = {
          isToMany: relatedObject.data.constructor === Array
        }
 
        relatedObject.get = getRelationship(this.store, relatedObject, relationshipConfig)
        relatedObject.load = loadRelationship(this.store, obj.id, obj.type, relatedObject, relationshipConfig)
 
        if (relationshipConfig.isToMany) {
          relatedObject.list = listRelationship(this.store, relatedObject)
        }
 
        relationships[currentRelationshipName] = relatedObject
      }
 
      // shorthand variant
      obj.loadRel = (relationshipName) => {
        return loadRelationship(this.store, obj.id, obj.type, relationships[relationshipName], getRelationshipConfig(relationships[relationshipName]))()
      }
      obj.rel = (relationshipName) => {
        if (getRelationshipConfig(relationships[relationshipName]).isToMany) {
          return listRelationship(this.store, relationships[relationshipName])()
        } else {
          return getRelationship(this.store, relationships[relationshipName], getRelationshipConfig(relationships[relationshipName]))()
        }
      }
    }
  }
 
  /**
  * Convenience method to get a spec-conforming version of
  * a resource object
  *
  * @param {Object} functionalResourceObject
  */
  static strip (functionalResourceObject) {
    return deref(functionalResourceObject)
  }
}
 
/**
 * Config Getter for the RelationshipMethod
 *
 * @param relatedObject
 * @return {{isToMany: boolean}}
 */
function getRelationshipConfig (relatedObject) {
  return {
    isToMany: relatedObject.data && relatedObject.data.constructor === Array
  }
}