More work on search
This commit is contained in:
@ -1,83 +1,20 @@
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const getAssetPaths = require('./npm/getAssetPaths')
|
const npmSearch = require('./npm/search')
|
||||||
const npmSearchIndex = require('./npm/searchIndex')
|
|
||||||
|
|
||||||
function enhanceHit(hit) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
const assetPaths = getAssetPaths(hit.name, hit.version)
|
|
||||||
|
|
||||||
if (assetPaths) {
|
|
||||||
// TODO: Double check the package metadata to ensure the files
|
|
||||||
// haven't moved from the paths in the index?
|
|
||||||
hit.assets = assetPaths.map(function (path) {
|
|
||||||
return `https://unpkg.com/${hit.name}@${hit.version}${path}`
|
|
||||||
})
|
|
||||||
|
|
||||||
resolve(hit)
|
|
||||||
} else {
|
|
||||||
resolve(hit)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function byRelevanceDescending(a, b) {
|
|
||||||
// Hits that have assets are more relevant.
|
|
||||||
return a.assets ? (b.assets ? 0 : -1) : (b.assets ? 1 : 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSearchServer() {
|
function createSearchServer() {
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
app.get('/', function (req, res) {
|
app.get('/', function (req, res) {
|
||||||
const { query, page = 0 } = req.query
|
const { query, page = 0 } = req.query
|
||||||
const hitsPerPage = 20
|
|
||||||
|
|
||||||
if (!query)
|
if (!query)
|
||||||
return res.status(403).send({ error: 'Missing ?query parameter' })
|
return res.status(403).send({ error: 'Missing ?query parameter' })
|
||||||
|
|
||||||
const params = {
|
npmSearch(query, page).then(function (result) {
|
||||||
typoTolerance: 'min',
|
res.send(result)
|
||||||
attributesToRetrieve: [
|
}, function (error) {
|
||||||
'name',
|
console.error(error)
|
||||||
'version',
|
res.status(500).send({ error: 'There was an error executing the search' })
|
||||||
'description',
|
|
||||||
'owner'
|
|
||||||
],
|
|
||||||
attributesToHighlight: null,
|
|
||||||
restrictSearchableAttributes: [
|
|
||||||
'name',
|
|
||||||
'description'
|
|
||||||
],
|
|
||||||
hitsPerPage,
|
|
||||||
page
|
|
||||||
}
|
|
||||||
|
|
||||||
npmSearchIndex.search(query, params, function (error, value) {
|
|
||||||
if (error) {
|
|
||||||
console.error(error)
|
|
||||||
res.status(500).send({ error: 'There was an error executing the search' })
|
|
||||||
} else {
|
|
||||||
Promise.all(
|
|
||||||
value.hits.map(enhanceHit)
|
|
||||||
).then(function (hits) {
|
|
||||||
hits.sort(byRelevanceDescending)
|
|
||||||
|
|
||||||
const totalHits = value.nbHits
|
|
||||||
const totalPages = value.nbPages
|
|
||||||
|
|
||||||
res.send({
|
|
||||||
query,
|
|
||||||
page,
|
|
||||||
hitsPerPage,
|
|
||||||
totalHits,
|
|
||||||
totalPages,
|
|
||||||
hits
|
|
||||||
})
|
|
||||||
}, function (error) {
|
|
||||||
console.error(error)
|
|
||||||
res.status(500).send({ error: 'There was an error executing the search' })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
const semver = require('semver')
|
||||||
const assetPathsIndex = require('./assetPathsIndex')
|
const assetPathsIndex = require('./assetPathsIndex')
|
||||||
|
|
||||||
function getAssetPaths(packageName, version) {
|
function getAssetPaths(packageName, version) {
|
||||||
|
88
server/npm/search.js
Normal file
88
server/npm/search.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
const searchIndex = require('./searchIndex')
|
||||||
|
const getAssetPaths = require('./getAssetPaths')
|
||||||
|
|
||||||
|
function enhanceHit(hit) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
const assetPaths = getAssetPaths(hit.name, hit.version)
|
||||||
|
|
||||||
|
if (assetPaths) {
|
||||||
|
// TODO: Double check the package metadata to ensure the files
|
||||||
|
// haven't moved from the paths in the index?
|
||||||
|
hit.assets = assetPaths.map(function (path) {
|
||||||
|
return `https://unpkg.com/${hit.name}@${hit.version}${path}`
|
||||||
|
})
|
||||||
|
|
||||||
|
resolve(hit)
|
||||||
|
} else {
|
||||||
|
resolve(hit)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function byRelevanceDescending(a, b) {
|
||||||
|
// Hits that have assets are more relevant.
|
||||||
|
return a.assets ? (b.assets ? 0 : -1) : (b.assets ? 1 : 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add concatenated name for more relevance for people spelling without spaces
|
||||||
|
// think: createreactnative instead of create-react-native-app
|
||||||
|
function concat(string) {
|
||||||
|
return string.replace(/[-/@_.]+/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function search(query, page) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
const hitsPerPage = 10
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
// typoTolerance: 'min',
|
||||||
|
optionalFacetFilters: `concatenatedName:${concat(query)}`,
|
||||||
|
facets: [ 'keywords' ],
|
||||||
|
attributesToHighlight: null,
|
||||||
|
attributesToRetrieve: [
|
||||||
|
'description',
|
||||||
|
'githubRepo',
|
||||||
|
'keywords',
|
||||||
|
'license',
|
||||||
|
'name',
|
||||||
|
'owner',
|
||||||
|
'version'
|
||||||
|
],
|
||||||
|
// restrictSearchableAttributes: [
|
||||||
|
// 'name',
|
||||||
|
// 'description',
|
||||||
|
// 'keywords'
|
||||||
|
// ],
|
||||||
|
hitsPerPage,
|
||||||
|
page
|
||||||
|
}
|
||||||
|
|
||||||
|
searchIndex.search(query, params, function (error, value) {
|
||||||
|
if (error) {
|
||||||
|
reject(error)
|
||||||
|
} else {
|
||||||
|
resolve(
|
||||||
|
Promise.all(
|
||||||
|
value.hits.map(enhanceHit)
|
||||||
|
).then(function (hits) {
|
||||||
|
hits.sort(byRelevanceDescending)
|
||||||
|
|
||||||
|
const totalHits = value.nbHits
|
||||||
|
const totalPages = value.nbPages
|
||||||
|
|
||||||
|
return {
|
||||||
|
query,
|
||||||
|
page,
|
||||||
|
hitsPerPage,
|
||||||
|
totalHits,
|
||||||
|
totalPages,
|
||||||
|
hits
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = search
|
Reference in New Issue
Block a user