summaryrefslogtreecommitdiff
path: root/src/pages/api/shop/search.js
blob: bab962372347e1ac64e9f5a8dfc76d32b2a3dbfb (plain)
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
import axios from 'axios'
import camelcaseObjectDeep from 'camelcase-object-deep'

export default async function handler(req, res) {
  const {
    q = '*',
    page = 1,
    brand = '',
    category = '',
    priceFrom = 0,
    priceTo = 0,
    orderBy = '',
    operation = 'AND',
    fq = '',
    limit = 30
  } = req.query

  let paramOrderBy = 'product_rating_f DESC'
  switch (orderBy) {
    case 'price-asc':
      paramOrderBy += ', price_discount_f ASC'
      break
    case 'price-desc':
      paramOrderBy += ', price_discount_f DESC'
      break
    case 'popular':
      paramOrderBy += ', search_rank_i DESC'
      break
    case 'stock':
      paramOrderBy += ', stock_total_f DESC'
      break
  }

  let offset = (page - 1) * limit
  let parameter = [
    'facet.field=manufacture_name',
    'facet.field=category_name',
    'facet=true',
    'indent=true',
    `facet.query=${escapeSolrQuery(q)}`,
    `q.op=${operation}`,
    `q=${escapeSolrQuery(q)}`,
    'qf=name_s',
    `start=${offset}`,
    `rows=${limit}`,
    `sort=${paramOrderBy}`,
    `fq=price_discount_f:[${priceFrom == '' ? '*' : priceFrom} TO ${priceTo == '' ? '*' : priceTo}]`
  ]

  if (brand) parameter.push(`fq=manufacture_name:${brand}`)
  if (category) parameter.push(`fq=category_name:${category}`)

  // Single fq in url params
  if (typeof fq === 'string') parameter.push(`fq=${fq}`)
  // Multi fq in url params
  if (Array.isArray(fq)) parameter = parameter.concat(fq.map((val) => `fq=${val}`))

  let result = await axios(process.env.SOLR_HOST + '/solr/product/select?' + parameter.join('&'))
  try {
    result.data.response.products = productResponseMap(result.data.response.docs)
    result.data.responseHeader.params.start = parseInt(result.data.responseHeader.params.start)
    result.data.responseHeader.params.rows = parseInt(result.data.responseHeader.params.rows)
    delete result.data.response.docs
    result.data = camelcaseObjectDeep(result.data)
    res.status(200).json(result.data)
  } catch (error) {
    res.status(400).json({ error: error.message })
  }
}

const escapeSolrQuery = (query) => {
  if (query == '*') return query

  const specialChars = /([\+\-\!\(\)\{\}\[\]\^"~\*\?:\\\/])/g
  const words = query.split(/\s+/)
  const escapedWords = words.map((word) => {
    if (specialChars.test(word)) {
      return `"${word.replace(specialChars, '\\$1')}"`
    }
    return word
  })

  return escapedWords.join(' ')
}

const productResponseMap = (products) => {
  return products.map((product) => {
    let productMapped = {
      id: product.product_id_i || '',
      image: product.image_s || '',
      code: product.default_code_s || '',
      name: product.name_s || '',
      lowestPrice: {
        price: product.price_f || 0,
        priceDiscount: product.price_discount_f || 0,
        discountPercentage: product.discount_f || 0
      },
      variantTotal: product.variant_total_i || 0,
      stockTotal: product.stock_total_f || 0,
      weight: product.weight_f || 0,
      manufacture: {},
      categories: []
    }

    if (product.manufacture_id_i && product.manufacture_name_s) {
      productMapped.manufacture = {
        id: product.manufacture_id_i || '',
        name: product.manufacture_name_s || ''
      }
    }

    productMapped.categories = [
      {
        id: product.category_id_i || '',
        name: product.category_name_s || ''
      }
    ]
    return productMapped
  })
}