All files / lib MemoryHandler.js

20.31% Statements 13/64
0% Branches 0/22
0% Functions 0/14
22.41% Lines 13/58
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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153  1x       1x       1x         1x           1x               1x                             1x                                         1x                                       1x                                   1x                                       1x                                           1x   1x            
'use strict'
const _ = {
  assign: require('lodash.assign')
}
 
const MemoryStore = module.exports = function MemoryStore () {
}
 
// resources represents out in-memory data store
const resources = { }
 
/**
  Handlers readiness status. This should be set to `true` once all handlers are ready to process requests.
 */
MemoryStore.prototype.ready = false
 
/**
  initialise gets invoked once for each resource that uses this hander.
  In this instance, we're allocating an array in our in-memory data store.
 */
MemoryStore.prototype.initialise = function (resourceConfig) {
  resources[resourceConfig.resource] = resourceConfig.examples || [ ]
  this.ready = true
}
 
/**
  Search for a list of resources, given a resource type.
 */
MemoryStore.prototype.search = function (request, callback) {
  const self = this
 
  let results = [].concat(resources[request.params.type])
  self._sortList(request, results)
  const resultCount = results.length
  if (request.params.page) {
    results = results.slice(request.params.page.offset, request.params.page.offset + request.params.page.limit)
  }
  return callback(null, MemoryStore._clone(results), resultCount)
}
 
/**
  Find a specific resource, given a resource type and and id.
 */
MemoryStore.prototype.find = (request, callback) => {
  // Pull the requested resource from the in-memory store
  const theResource = resources[request.params.type].filter(anyResource => anyResource.id === request.params.id).pop()
 
  // If the resource doesn't exist, error
  if (!theResource) {
    return callback({ // eslint-disable-line standard/no-callback-literal
      status: '404',
      code: 'ENOTFOUND',
      title: 'Requested resource does not exist',
      detail: `There is no ${request.params.type} with id ${request.params.id}`
    })
  }
 
  // Return the requested resource
  return callback(null, MemoryStore._clone(theResource))
}
 
/**
  Create (store) a new resource given a resource type and an object.
 */
MemoryStore.prototype.create = (request, newResource, callback) => {
  // Check to see if the ID already exists
  const index = MemoryStore._indexOf(resources[request.params.type], newResource)
  if (index !== -1) {
    return callback({ // eslint-disable-line standard/no-callback-literal
      status: '403',
      code: 'EFORBIDDEN',
      title: 'Requested resource already exists',
      detail: `The requested resource already exists of type ${request.params.type} with id ${request.params.id}`
    })
  }
  // Push the newResource into our in-memory store.
  resources[request.params.type].push(newResource)
  // Return the newly created resource
  return callback(null, MemoryStore._clone(newResource))
}
 
/**
  Delete a resource, given a resource type and and id.
 */
MemoryStore.prototype.delete = function (request, callback) {
  // Find the requested resource
  this.find(request, (err, theResource) => {
    if (err) return callback(err)
 
    // Remove the resource from the in-memory store.
    const index = MemoryStore._indexOf(resources[request.params.type], theResource)
    resources[request.params.type].splice(index, 1)
 
    // Return with no error
    return callback()
  })
}
 
/**
  Update a resource, given a resource type and id, along with a partialResource.
  partialResource contains a subset of changes that need to be merged over the original.
 */
MemoryStore.prototype.update = function (request, partialResource, callback) {
  // Find the requested resource
  this.find(request, (err, theResource) => {
    if (err) return callback(err)
 
    // Merge the partialResource over the original
    theResource = _.assign(theResource, partialResource)
 
    // Push the newly updated resource back into the in-memory store
    const index = MemoryStore._indexOf(resources[request.params.type], theResource)
    resources[request.params.type][index] = theResource
 
    // Return the newly updated resource
    return callback(null, MemoryStore._clone(theResource))
  })
}
 
/**
  Internal helper function to sort data
 */
MemoryStore.prototype._sortList = (request, list) => {
  let attribute = request.params.sort
  if (!attribute) return
 
  let ascending = 1
  attribute = (`${attribute}`)
  if (attribute[0] === '-') {
    ascending = -1
    attribute = attribute.substring(1, attribute.length)
  }
 
  list.sort((a, b) => {
    if (typeof a[attribute] === 'string') {
      return a[attribute].localeCompare(b[attribute]) * ascending
    } else if (typeof a[attribute] === 'number') {
      return (a[attribute] - b[attribute]) * ascending
    } else {
      return 0
    }
  })
}
 
MemoryStore._clone = obj => JSON.parse(JSON.stringify(obj))
 
MemoryStore._indexOf = (list, obj) => {
  for (const i in list) {
    if (list[i].id === obj.id) return i
  }
  return -1
}