Update how SearchController and searching works

This commit is contained in:
Robbie Antenesse 2020-02-07 15:28:59 -07:00
parent 326747c0ce
commit 5ab6d36314
2 changed files with 36 additions and 38 deletions

View File

@ -11,16 +11,8 @@ const defaultSearchOptions = {
} }
class SearchController { class SearchController {
constructor(sequelizeModels, searchTerm, options = defaultSearchOptions) { constructor(sequelizeModels) {
this.models = sequelizeModels; this.models = sequelizeModels;
this.searchTerm = searchTerm;
this.searchBy = options.searchBy.replace('title', 'name').replace('author', 'description');
this.source = options.source;
this.lang = options.language;
}
get hasQuery() {
return typeof this.searchTerm !== 'undefined' && this.searchTerm !== '';
} }
get bookReferenceSearchAttributes() { get bookReferenceSearchAttributes() {
@ -59,52 +51,58 @@ class SearchController {
}; };
} }
async search() { async search(searchTerm, options = defaultSearchOptions) {
const bookReferences = await this.searchReferences(); const searchBy = options.searchBy.replace('title', 'name').replace('author', 'description');
const { source, language } = options;
const bookReferences = await this.searchReferences(searchTerm, options);
let searchResults; let searchResults;
switch (this.source) { switch (source) {
case 'openlibrary': { case 'openlibrary': {
searchResults = await this.searchOpenLibrary(this.searchBy); searchResults = await this.searchOpenLibrary(searchBy);
break; break;
} }
case 'inventaire': case 'inventaire':
default: { default: {
searchResults = await quickSearchInventaire(this.searchTerm, this.lang); searchResults = await quickSearchInventaire(searchTerm, language);
break; break;
} }
} }
// Add any search results that match refs with the same URI and delete from results array // Add any search results that match refs with the same URI and delete from results array
const urisToCheck = searchResults.filter( const urisToCheck = searchResults.filter(
result => !bookReferences.some(ref => result.uri === ref.sources[this.source]) result => !bookReferences.some(ref => result.uri === ref.sources[source])
).map(result => result.uri); ).map(result => result.uri);
let extraReferences = [];
if (urisToCheck.length > 0) { if (urisToCheck.length > 0) {
const foundReferences = await this.searchReferencesBySourceCodes(this.source, urisToCheck); extraReferences = await this.searchReferencesBySourceCodes(source, urisToCheck);
return [
...bookReferences,
...foundReferences,
...searchResults.filter(result => !urisToCheck.includes(result.uri)),
];
} }
return [ return [
...bookReferences, ...bookReferences,
...searchResults.filter(result => result !== null), ...extraReferences,
...searchResults.filter( // Only show the rest of the search results
result => !extraReferences.some(
ref => result.uri === ref.sources[source]
)
),
]; ];
} }
async searchReferences() { async searchReferences(searchTerm, options = defaultSearchOptions) {
const searchBy = options.searchBy.replace('title', 'name').replace('author', 'description');
const { language } = options;
const { BookReference } = this.models; const { BookReference } = this.models;
const exact = await BookReference.findAll({ const exact = await BookReference.findAll({
where: { where: {
[Op.and]: [ // All of the contained cases are true [Op.and]: [ // All of the contained cases are true
{ {
[this.searchBy]: this.searchTerm, // searchBy is exactly searchTerm [searchBy]: searchTerm, // searchBy is exactly searchTerm
}, },
{ {
locale: this.lang, locale: language,
}, },
] ]
}, },
@ -122,12 +120,12 @@ class SearchController {
where: { where: {
[Op.and]: [ // All of the contained cases are true [Op.and]: [ // All of the contained cases are true
{ {
[this.searchBy]: { // `name` or `description` [searchBy]: { // `name` or `description`
[Op.substring]: this.searchTerm, // LIKE '%searchTerm%' [Op.substring]: searchTerm, // LIKE '%searchTerm%'
}, },
}, },
{ {
locale: this.lang, locale: language,
}, },
] ]
}, },
@ -155,7 +153,7 @@ class SearchController {
async searchReferencesBySourceCodes(source, sourceIds) { async searchReferencesBySourceCodes(source, sourceIds) {
const sourceJSONKey = `"${source}"`; // Enable searching withing JSON column. const sourceJSONKey = `"${source}"`; // Enable searching withing JSON column.
return await this.models.BookReference.findOne({ return await this.models.BookReference.findAll({
where: { where: {
[Op.or]: sourceIds.map(sourceId => ({ [Op.or]: sourceIds.map(sourceId => ({
source: { source: {
@ -218,14 +216,14 @@ class SearchController {
} }
async searchWikiBooks(term) { async searchWikiBooks(term) {
if (!this.hasQuery) { if (!term) {
return []; return [];
} }
const query = this.mediaWikiQuery('https://en.wikibooks.org/w/api.php', { const query = this.mediaWikiQuery('https://en.wikibooks.org/w/api.php', {
action: 'query', action: 'query',
list: 'search', list: 'search',
srsearch: this.searchTerm, srsearch: term,
srprop: '', srprop: '',
}); });
query(response => { query(response => {
@ -257,19 +255,19 @@ class SearchController {
}); });
} }
async searchOpenLibrary(searchBy = 'title') { async searchOpenLibrary(searchTerm, searchBy = 'title') {
if (!this.hasQuery) { if (!searchTerm) {
return []; return [];
} }
return fetch(`https://openlibrary.org/search.json?${searchBy}=${encodeURIComponent(this.searchTerm)}`) return fetch(`https://openlibrary.org/search.json?${searchBy}=${encodeURIComponent(searchTerm)}`)
.then(res => res.json()) .then(res => res.json())
.then(response => { .then(response => {
if (!response.hasOwnProperty('docs')) { if (!response.hasOwnProperty('docs')) {
return []; return [];
} }
const booksController = new BooksController('openLibrary', undefined, this.lang); const booksController = new BooksController('openLibrary');
// Format the response into usable objects // Format the response into usable objects
const docs = response.docs.map(doc => { const docs = response.docs.map(doc => {

View File

@ -6,9 +6,9 @@ async function routes(fastify, options) {
const searchBy = typeof request.query.by !== 'undefined' ? request.query.by.trim() : 'title'; const searchBy = typeof request.query.by !== 'undefined' ? request.query.by.trim() : 'title';
const language = typeof request.query.lang !== 'undefined' ? request.query.lang.trim().split('-')[0] : undefined; // Get base language in cases like 'en-US' const language = typeof request.query.lang !== 'undefined' ? request.query.lang.trim().split('-')[0] : undefined; // Get base language in cases like 'en-US'
const source = typeof request.query.source !== 'undefined' ? request.query.source.trim() : undefined; // Get base language in cases like 'en-US' const source = typeof request.query.source !== 'undefined' ? request.query.source.trim() : undefined; // Get base language in cases like 'en-US'
const controller = new SearchController(fastify.models, searchTerm, { searchBy, source, language }); const controller = new SearchController(fastify.models);
return await controller.search(); return await controller.search(searchTerm, { searchBy, source, language });
}); });
fastify.get('/api/search/cover', async (request, reply) => { fastify.get('/api/search/cover', async (request, reply) => {