lib/MemoryHandler.js
'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
}