rexxars/vinmonopolet

View on GitHub
src/retrievers/getProducts.js

Summary

Maintainability
A
2 hrs
Test Coverage
A
100%
const objectAssign = require('object-assign')
const Product = require('../models/Product')
const Pagination = require('../models/Pagination')
const FacetValue = require('../models/FacetValue')
const request = require('../util/request')
const arrayify = require('../util/arrayify')
const oneOfMessage = require('../util/oneOfMessage')

const defaults = {limit: 50, page: 1}
const sortFields = ['relevance', 'name', 'price']
const sortOrders = ['asc', 'desc']
const sortTakesOrder = ['name', 'price']

function getProducts(opts) {
  const options = objectAssign({}, defaults, opts || {})
  const query = {
    pageSize: options.limit,
    currentPage: Math.max(0, options.page - 1),
    fields: 'FULL',
  }

  // The `query` query parameter (heh) has the following syntax (a bit weird, this);
  // freeTextSearch:sort:facetKey1:facetValue1:facetKey2:facetValue2
  const queryParts = {
    freeTextSearch: '',
    sort: 'relevance',
    facets: []
  }

  if (options.query) {
    queryParts.freeTextSearch = options.query
  }

  const sort = getSortParam(options.sort)
  if (sort) {
    queryParts.sort = sort
  }

  if (options.facet || options.facets) {
    const facets = arrayify(options.facet || options.facets)
    queryParts.facets = facets.map(FacetValue.cooerce).map(val => val.query)
  }

  // Serialize actual "query" query param as outlined above
  query.query = [queryParts.freeTextSearch, queryParts.sort]
    .concat(queryParts.facets)
    .join(':')

  const getter = request[options.onlyCount ? 'head' : 'get']
  const req = getter('/products/search', {query})

  if (options.onlyCount) {
    return req.then(res => Number(res.headers['x-total-count']))
  }

  return req.then(res => ({
    products: (res.products || []).map(i => new Product(i)),
    pagination: new Pagination(res.pagination, options, getProducts)
  }))
}

getProducts.count = opts => {
  return getProducts(objectAssign({}, opts, {onlyCount: true}))
}

function getSortParam(sort) {
  if (!sort) {
    return undefined
  }

  const [sortField, sortOrder] = arrayify(sort)

  if (sortFields.indexOf(sortField) === -1) {
    throw new Error(`"options.sort[0]" is not valid. ${oneOfMessage(sortFields)}`)
  }

  if (sortOrder && sortOrders.indexOf(sortOrder) === -1) {
    throw new Error(`"options.sort[1]" is not valid. ${oneOfMessage(sortOrders)}`)
  }

  const takesOrder = sortTakesOrder.indexOf(sortField) !== -1
  let newSortOrder = sortOrder
  if (!sortOrder && takesOrder) {
    newSortOrder = sortOrders[0]
  } else if (sortOrder && !takesOrder) {
    newSortOrder = undefined
  }

  return [sortField, newSortOrder].filter(Boolean).join('-')
}

module.exports = getProducts