holidayextras/jsonapi-server

View on GitHub
lib/graphQl/resolvers.js

Summary

Maintainability
A
0 mins
Test Coverage
'use strict'
const resolvers = module.exports = { }

const _ = {
  assign: require('lodash.assign')
}
const rerouter = require('../rerouter.js')
const jsonApi = require('../..')

resolvers.search = (resourceConfig, attribute, parent, args, req, ast) => {
  let path
  // If we don't have a JSON:API resource, go get it
  if (!parent) {
    path = jsonApi._apiConfig.pathPrefix + resourceConfig.resource
    return resolvers.rerouteTo('GET', path, { }, req, ast)
  }
  // Simple attributes can be plucked from the JSON:API resource
  if (!resourceConfig.attributes[attribute]._settings) {
    return parent.attributes[attribute]
  }
  // Related resources need to be requested via the related link
  path = parent.relationships[attribute].links.related
  return resolvers.rerouteTo('GET', path, { }, req, ast)
}

resolvers.create = (resourceConfig, parent, args, req, ast) => {
  const path = jsonApi._apiConfig.pathPrefix + resourceConfig.resource
  const data = resolvers.generateResourceFromArgs(args, resourceConfig)
  return resolvers.rerouteTo('POST', path, { data }, req, ast)
}

resolvers.update = (resourceConfig, parent, args, req, ast) => {
  const path = `${jsonApi._apiConfig.pathPrefix + resourceConfig.resource}/${args[resourceConfig.resource].id}`
  const data = resolvers.generateResourceFromArgs(args, resourceConfig)
  return resolvers.rerouteTo('PATCH', path, { data }, req, ast)
}

resolvers.delete = (resourceConfig, parent, args, req, ast) => {
  const path = `${jsonApi._apiConfig.pathPrefix + resourceConfig.resource}/${args.id}`
  let resource
  return resolvers.rerouteTo('GET', path, { }, req, ast)
    .then(originalResource => {
      resource = originalResource
      return resolvers.rerouteTo('DELETE', path, { }, req, ast)
    }).then(() => resource)
}

resolvers.rerouteTo = (method, path, args, req, ast) => new Promise((resolve, reject) => {
  rerouter.route({
    method,
    uri: path,
    params: _.assign({
      fields: resolvers.generateFieldsQueryFromAst(ast),
      filter: resolvers.generateFilterQueryFromAst(ast)
    }, args),
    originalRequest: {
      headers: req.headers || { },
      cookies: req.cookies || { }
    }
  }, (err, json) => {
    if (err) return reject(err.errors.map(e => e.detail))
    resolve(json.data)
  })
})

resolvers.generateResourceFromArgs = (args, resourceConfig) => {
  if ((Object.keys(args).length === 1) && (args[resourceConfig.resource])) {
    args = args[resourceConfig.resource]
  }

  const data = {
    type: resourceConfig.resource,
    attributes: { },
    relationships: { }
  }

  Object.keys(resourceConfig.attributes).forEach(attribute => {
    const joiSchema = resourceConfig.attributes[attribute]
    if (!args[attribute]) return
    if (!joiSchema._settings) {
      data.attributes[attribute] = args[attribute]
    } else {
      data.relationships[attribute] = {
        data: args[attribute]
      };
      [].concat(data.relationships[attribute].data).forEach(relation => {
        relation.type = (joiSchema._settings.__one || joiSchema._settings.__many)[0]
      })
    }
  })

  return data
}

resolvers.generateFieldsQueryFromAst = ast => {
  const arrays = (ast.fieldASTs || []).map(fieldAST => fieldAST.selectionSet.selections || [ ])
  const combined = [].concat.apply([], arrays)
  let fields = combined.map(thing => (thing.name || { }).value).filter(a => a)
  fields = fields.join(',')
  return fields
}

resolvers.generateFilterQueryFromAst = ast => {
  const arrays = (ast.fieldNodes || []).map(function (fieldAST) {
    return fieldAST.arguments || [ ]
  })
  const combined = [].concat.apply([], arrays)
  const filter = { }
  combined.forEach(thing => {
    filter[thing.name.value] = thing.value.value
  })
  return filter
}