Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to search books #6

Merged
merged 4 commits into from
May 3, 2024
Merged

Conversation

nklimovych
Copy link
Owner

No description provided.

Copy link

@karma-o karma-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some suggestions for refactors


public record BookSearchParametersDto(
String[] author,
String[] title,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see much sense in getting several titles, we usually do a search with partial match of book title with some single search string that we receive here

import org.springframework.stereotype.Component;

@Component
public class TitleSpecificationProvider extends AbstractSpecificationProvider<Book> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and so as a follow up to the comment above, I would override the method that you have in abstract spec provider with something that would use SQL LIKE to have a partial match search

Comment on lines 10 to 11
private static final int MIN_PRICE = 0;
private static final int MAX_PRICE = 1;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's not just the price these are indexes

Comment on lines 13 to 22
private final List<SpecificationProvider<Book>> bookSpecificationProviders;

@Override
public SpecificationProvider<Book> getSpecificationProvider(String key) {
return bookSpecificationProviders.stream()
.filter(p -> p.getKey().equals(key))
.findFirst()
.orElseThrow(() -> new RuntimeException(
"Can't find specification provider for " + key));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

having a map here instead of a list would be more efficient, but that is not too important

Comment on lines 43 to 46
.getSpecification(new String[]{
params.minPrice(),
params.maxPrice()
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think it is a good approach to build an array and operate it instead of clean and structured data in object that we have. Let's remove AbstractSpecificationProvider and make SpecificationProvider.getSpecification() receive not a string[] but a whole BookSearchParametersDto where the impl classes will take only the data that they need to.

}

private Specification<Book> getPriceSpecification(BookSearchParametersDto params) {
if (params.minPrice() != null && params.maxPrice() != null) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we receive only the max price filter, should it be ignored?

Comment on lines 20 to 27
return Stream.of(
getSpecification(params.author(), BookSearchParameter.AUTHOR.getKey()),
getSpecification(params.title(), BookSearchParameter.TITLE.getKey()),
getSpecification(params.isbn(), BookSearchParameter.ISBN.getKey()),
getPriceSpecification(params)
)
.filter(Objects::nonNull)
.reduce(Specification.where(null), Specification::and);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

…SpecificationProvider class, made changes in parameter specification providers. Change implementation of build() method id BookSpecificationBuilder.
@nklimovych nklimovych requested a review from karma-o May 2, 2024 20:24
Copy link

@karma-o karma-o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job! Left several suggestions for the future in case you'd want to improve that part later on

Comment on lines +25 to +31
Map<String, Function<BookSearchParametersDto, Specification<Book>>>
specificationMap = Map.of(
AUTHOR, params -> params.author() != null ? getSpecification(params, AUTHOR) : null,
TITLE, params -> params.title() != null ? getSpecification(params, TITLE) : null,
ISBN, params -> params.isbn() != null ? getSpecification(params, ISBN) : null,
PRICE, params -> (params.minPrice() != null || params.maxPrice() != null)
? getSpecification(params, PRICE) : null
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks a bit too complicated, would be nice to simplify it somehow

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand but i really want to avoid 4 if in row)

Comment on lines +18 to +20
public Specification<Book> getSpecification(BookSearchParametersDto params) {
return (root, query, criteriaBuilder) -> criteriaBuilder.like(
root.get(getKey()), "%" + params.isbn() + "%");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could actually organize a search by 2 fields, like so:
some searchString param that we get in dto, is LIKE ISBN OR LIKE title but that is a feature for another day 😄

Comment on lines +13 to +14
private static final int DEFAULT_MIN_PRICE = 0;
private static final int DEFAULT_MAX_PRICE = Integer.MAX_VALUE;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A point for optimizing the queries. Would be nice to not send the default params when we did not receive them in DTO because they are redundant, like:

  • if we do not receive minPrice & maxPrice - query should not have that price filtration at all
  • if we receive only minPrice - query should be just where price > minPrice
  • if we receive only maxPrice - query should be just where price < minPrice

@nklimovych nklimovych merged commit 2201922 into main May 3, 2024
2 checks passed
@nklimovych nklimovych deleted the implement-search-endpoint branch May 3, 2024 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants