Skip to content

Commit

Permalink
refactor: move findBooksBySearchString
Browse files Browse the repository at this point in the history
- move findBooksBySearchString to the search lib to lighten to load in the actions lib, and as it's a better fit in search
  • Loading branch information
dylants committed Apr 26, 2024
1 parent 5409dfd commit f4e91b8
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 106 deletions.
2 changes: 1 addition & 1 deletion src/app/search/SearchCommandContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import SearchCommand, {
SearchCommandResult,
} from '@/components/search/SearchCommand';
import { findBooksBySearchString } from '@/lib/actions/book';
import { findBooksBySearchString } from '@/lib/search/book';
import BookHydrated from '@/types/BookHydrated';
import { useDebounceCallback } from '@react-hook/debounce';
import { useRouter } from 'next/navigation';
Expand Down
66 changes: 0 additions & 66 deletions src/lib/actions/book.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
buildAuthorsInput,
buildPublisherInput,
findBooksBySearchString,
getBook,
getBooks,
upsertBook,
Expand Down Expand Up @@ -207,71 +206,6 @@ describe('book actions', () => {
});
});

describe('findBooksBySearchString', () => {
it('should find books that contain "Book"', async () => {
prismaMock.book.findMany.mockResolvedValue([book1, book2, book3]);

const result = await findBooksBySearchString('Book');

expect(prismaMock.book.findMany).toHaveBeenCalledWith({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: [
{ authors: { some: { name: { search: 'Book' } } } },
{ title: { search: 'Book' } },
],
},
});
expect(result).toEqual([book1, book2, book3]);
});

it('should process multiple words', async () => {
prismaMock.book.findMany.mockResolvedValue([book2]);

const result = await findBooksBySearchString('the other book');

expect(prismaMock.book.findMany).toHaveBeenCalledWith({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: [
{ authors: { some: { name: { search: 'the & other & book' } } } },
{ title: { search: 'the & other & book' } },
],
},
});
expect(result).toEqual([book2]);
});

it('should process ISBN13', async () => {
prismaMock.book.findMany.mockResolvedValue([book2]);

const result = await findBooksBySearchString('9780765376671');

expect(prismaMock.book.findMany).toHaveBeenCalledWith({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: [{ isbn13: { equals: 9780765376671 } }],
},
});
expect(result).toEqual([book2]);
});
});

describe('getBook', () => {
it('should provide the correct input to prisma', async () => {
prismaMock.book.findUnique.mockResolvedValue(book1);
Expand Down
38 changes: 0 additions & 38 deletions src/lib/actions/book.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import BookHydrated from '@/types/BookHydrated';
import { Book, Prisma, ProductType } from '@prisma/client';
import { serializeBookSource } from '@/lib/serializers/book-source';
import NegativeBookQuantityError from '@/lib/errors/NegativeBookQuantityError';
import _ from 'lodash';

export async function buildAuthorsInput(
tx: Prisma.TransactionClient,
Expand Down Expand Up @@ -252,43 +251,6 @@ export async function getBooks({
};
}

export async function findBooksBySearchString(
searchString: string,
): Promise<Array<BookHydrated>> {
let whereClauses: Prisma.BookWhereInput[];
const searchStringNumber = _.toNumber(searchString);
if (_.isFinite(searchStringNumber)) {
whereClauses = [{ isbn13: { equals: searchStringNumber } }];
} else {
const search = searchString.split(' ').join(' & ');
whereClauses = [
{ authors: { some: { name: { search } } } },
{ title: { search } },
];
}

const rawBooks = await prisma.book.findMany({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: whereClauses,
},
});

const books = rawBooks.map((book) => ({
...book,
publisher: serializeBookSource(book.publisher),
}));

logger.trace('books found: %j', books);

return books;
}

export async function getBook(
isbn13: Book['isbn13'],
): Promise<BookHydrated | null> {
Expand Down
73 changes: 72 additions & 1 deletion src/lib/search/book.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { findBookByIsbn13 } from '@/lib/search/book';
import { fakeBookHydrated } from '@/lib/fakes/book';
import { findBookByIsbn13, findBooksBySearchString } from '@/lib/search/book';
import { prismaMock } from '../../../test-setup/prisma-mock.setup';

const mockGetBook = jest.fn();
jest.mock('../actions/book', () => ({
Expand All @@ -17,6 +19,10 @@ jest.mock('./google', () => ({
}));

describe('book search', () => {
const book1 = fakeBookHydrated();
const book2 = fakeBookHydrated();
const book3 = fakeBookHydrated();

beforeEach(() => {
mockGetBook.mockReset();
mockTransformBookHydratedToBookFormInput.mockReset();
Expand Down Expand Up @@ -54,4 +60,69 @@ describe('book search', () => {
expect(result).toEqual('google search book');
});
});

describe('findBooksBySearchString', () => {
it('should find books that contain "Book"', async () => {
prismaMock.book.findMany.mockResolvedValue([book1, book2, book3]);

const result = await findBooksBySearchString('Book');

expect(prismaMock.book.findMany).toHaveBeenCalledWith({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: [
{ authors: { some: { name: { search: 'Book' } } } },
{ title: { search: 'Book' } },
],
},
});
expect(result).toEqual([book1, book2, book3]);
});

it('should process multiple words', async () => {
prismaMock.book.findMany.mockResolvedValue([book2]);

const result = await findBooksBySearchString('the other book');

expect(prismaMock.book.findMany).toHaveBeenCalledWith({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: [
{ authors: { some: { name: { search: 'the & other & book' } } } },
{ title: { search: 'the & other & book' } },
],
},
});
expect(result).toEqual([book2]);
});

it('should process ISBN13', async () => {
prismaMock.book.findMany.mockResolvedValue([book2]);

const result = await findBooksBySearchString('9780765376671');

expect(prismaMock.book.findMany).toHaveBeenCalledWith({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: [{ isbn13: { equals: 9780765376671 } }],
},
});
expect(result).toEqual([book2]);
});
});
});
45 changes: 45 additions & 0 deletions src/lib/search/book.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import { getBook } from '@/lib/actions/book';
import logger from '@/lib/logger';
import prisma from '@/lib/prisma';
import { googleBookSearch } from '@/lib/search/google';
import { serializeBookSource } from '@/lib/serializers/book-source';
import { transformBookHydratedToBookFormInput } from '@/lib/transformers/book';
import BookFormInput from '@/types/BookFormInput';
import BookHydrated from '@/types/BookHydrated';
import { Prisma } from '@prisma/client';
import _ from 'lodash';

/**
* Searches to find a Book first internally, and if not found, then externally.
Expand All @@ -30,3 +35,43 @@ export async function findBookByIsbn13({
logger.trace('book not found internally, using google search...');
return googleBookSearch({ isbn13 });
}

/**
* Searches internally to find a book
*/
export async function findBooksBySearchString(
searchString: string,
): Promise<Array<BookHydrated>> {
let whereClauses: Prisma.BookWhereInput[];
const searchStringNumber = _.toNumber(searchString);
if (_.isFinite(searchStringNumber)) {
whereClauses = [{ isbn13: { equals: searchStringNumber } }];
} else {
const search = searchString.split(' ').join(' & ');
whereClauses = [
{ authors: { some: { name: { search } } } },
{ title: { search } },
];
}

const rawBooks = await prisma.book.findMany({
include: {
authors: true,
format: true,
genre: true,
publisher: true,
},
where: {
OR: whereClauses,
},
});

const books = rawBooks.map((book) => ({
...book,
publisher: serializeBookSource(book.publisher),
}));

logger.trace('books found: %j', books);

return books;
}

0 comments on commit f4e91b8

Please sign in to comment.