Skip to content

Commit

Permalink
feat : polish search query (#1622)
Browse files Browse the repository at this point in the history
* feat : polish search query

* implement review comments
  • Loading branch information
rajadilipkolli authored Jan 8, 2025
1 parent e072f7c commit aa9cac3
Show file tree
Hide file tree
Showing 16 changed files with 216 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;

@Data
@ConfigurationProperties("application")
public class ApplicationProperties {
private Cors cors = new Cors();

@NestedConfigurationProperty private Cors cors = new Cors();

@Data
public static class Cors {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.domain.ReactiveAuditorAware;
import org.springframework.data.r2dbc.config.EnableR2dbcAuditing;
import org.springframework.r2dbc.connection.TransactionAwareConnectionFactoryProxy;
import reactor.core.publisher.Mono;

@Configuration
@EnableR2dbcAuditing
@Configuration(proxyBeanMethods = false)
@EnableR2dbcAuditing(auditorAwareRef = "myAuditorProvider", modifyOnCreate = false)
public class JooqConfiguration {

@Bean
public ReactiveAuditorAware<String> myAuditorProvider() {
return () -> Mono.justOrEmpty("appUser");
}

@Bean
DSLContext dslContext(ConnectionFactory connectionFactory) {
return DSL.using(new TransactionAwareConnectionFactoryProxy(connectionFactory)).dsl();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
package com.example.jooq.r2dbc.entities;

import java.util.Objects;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(value = "posts_tags")
public class PostTagRelation {

Expand All @@ -24,4 +14,47 @@ public class PostTagRelation {

@Column("tag_id")
private UUID tagId;

public PostTagRelation() {}

public PostTagRelation(UUID postId, UUID tagId) {
this.postId = postId;
this.tagId = tagId;
}

public UUID getPostId() {
return postId;
}

public PostTagRelation setPostId(UUID postId) {
this.postId = postId;
return this;
}

public UUID getTagId() {
return tagId;
}

public PostTagRelation setTagId(UUID tagId) {
this.tagId = tagId;
return this;
}

@Override
public String toString() {
return new ToStringBuilder(this).append("postId", postId).append("tagId", tagId).toString();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PostTagRelation)) return false;
PostTagRelation that = (PostTagRelation) o;
return Objects.equals(postId, that.postId) && Objects.equals(tagId, that.tagId);
}

@Override
public int hashCode() {
return Objects.hash(postId, tagId);
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
package com.example.jooq.r2dbc.entities;

import java.util.Objects;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(value = "tags")
public class Tags {

Expand All @@ -27,7 +17,41 @@ public class Tags {
@Column("name")
private String name;

public Tags(String name) {
public Tags() {}

public UUID getId() {
return id;
}

public Tags setId(UUID id) {
this.id = id;
return this;
}

public String getName() {
return name;
}

public Tags setName(String name) {
this.name = name;
return this;
}

@Override
public String toString() {
return new ToStringBuilder(this).append("id", id).append("name", name).toString();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tags)) return false;
Tags tags = (Tags) o;
return Objects.equals(name, tags.name);
}

@Override
public int hashCode() {
return Objects.hash(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.example.jooq.r2dbc.service.PostService;
import com.example.jooq.r2dbc.utils.AppConstants;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
Expand All @@ -22,10 +21,14 @@
import reactor.core.publisher.Mono;

@Component
@RequiredArgsConstructor
public class PostHandler {

private final PostService postService;

public PostHandler(PostService postService) {
this.postService = postService;
}

@Loggable
public Mono<ServerResponse> getAll(ServerRequest req) {
return ok().body(this.postService.findAll(), PostSummary.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.example.jooq.r2dbc.service.TagService;
import com.example.jooq.r2dbc.utils.AppConstants;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
Expand All @@ -20,32 +19,35 @@
import reactor.core.publisher.Mono;

@Component
@RequiredArgsConstructor
@Loggable
public class TagHandler {

// Service responsible for handling Tag-related business logic
private final TagService tagService;

public TagHandler(TagService tagService) {
this.tagService = tagService;
}

// Retrieve all tags based on query parameters for sorting and pagination
public Mono<ServerResponse> getAll(ServerRequest req) {
// Extracting and setting sort direction and field from query parameters
String sortDir = req.queryParam("sortDir").orElse(AppConstants.DEFAULT_SORT_DIRECTION);
String sortBy = req.queryParam("sortBy").orElse(AppConstants.DEFAULT_SORT_BY);
String sortDir = req.queryParam("sortDir").orElse(AppConstants.DEFAULT_SORT_DIRECTION);
Sort sort =
sortDir.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortBy).ascending()
: Sort.by(sortBy).descending();

// Creating Pageable instance for pagination
int pageNo =
req.queryParam("pageNo")
.map(Integer::parseInt)
.orElse(AppConstants.DEFAULT_PAGE_NUMBER);
int pageSize =
req.queryParam("pageSize")
.map(Integer::parseInt)
.orElse(AppConstants.DEFAULT_PAGE_SIZE);
int pageNo =
req.queryParam("pageNo")
.map(Integer::parseInt)
.orElse(AppConstants.DEFAULT_PAGE_NUMBER);
Pageable pageable = PageRequest.of(pageNo, pageSize, sort);

// Returning paginated result of tags
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package com.example.jooq.r2dbc.repository.custom.impl;

import static com.example.jooq.r2dbc.testcontainersflyway.db.Tables.*;
import static com.example.jooq.r2dbc.testcontainersflyway.db.Tables.POSTS;
import static com.example.jooq.r2dbc.testcontainersflyway.db.Tables.POSTS_TAGS;
import static com.example.jooq.r2dbc.testcontainersflyway.db.Tables.POST_COMMENTS;
import static com.example.jooq.r2dbc.testcontainersflyway.db.Tables.TAGS;
import static org.jooq.impl.DSL.multiset;
import static org.jooq.impl.DSL.select;

import com.example.jooq.r2dbc.model.response.PostCommentResponse;
import com.example.jooq.r2dbc.model.response.PostResponse;
import com.example.jooq.r2dbc.repository.custom.CustomPostRepository;
import com.example.jooq.r2dbc.testcontainersflyway.db.tables.PostComments;
import com.example.jooq.r2dbc.testcontainersflyway.db.tables.Posts;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Record1;
import org.jooq.impl.DSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
Expand All @@ -23,6 +25,7 @@

public class CustomPostRepositoryImpl extends JooqSorting implements CustomPostRepository {

private static final Logger log = LoggerFactory.getLogger(CustomPostRepositoryImpl.class);
private final DSLContext dslContext;

public CustomPostRepositoryImpl(DSLContext dslContext) {
Expand All @@ -31,59 +34,79 @@ public CustomPostRepositoryImpl(DSLContext dslContext) {

@Override
public Mono<Page<PostResponse>> findByKeyword(String keyword, Pageable pageable) {
Condition where = DSL.trueCondition();
log.debug("Searching posts with keyword: {}, pageable: {}", keyword, pageable);
// Build the where condition dynamically
Condition condition = DSL.trueCondition();
if (StringUtils.hasText(keyword)) {
where = where.and(POSTS.TITLE.likeIgnoreCase("%" + keyword + "%"));
condition =
condition.and(
DSL.or(
POSTS.TITLE.likeIgnoreCase(
DSL.concat(
DSL.val("%"), DSL.val(keyword), DSL.val("%"))),
POSTS.CONTENT.likeIgnoreCase(
DSL.concat(
DSL.val("%"),
DSL.val(keyword),
DSL.val("%")))));
}
var dataSql =

// Construct the main data SQL query
var dataQuery =
dslContext
.select(
.selectDistinct(
POSTS.ID,
POSTS.TITLE,
POSTS.CONTENT,
// Fetch comments as a multiset
multiset(
select(
PostComments.POST_COMMENTS.ID,
PostComments.POST_COMMENTS.CONTENT,
PostComments.POST_COMMENTS
.CREATED_AT)
.from(PostComments.POST_COMMENTS)
.where(
PostComments.POST_COMMENTS.POST_ID
.eq(Posts.POSTS.ID)))
POST_COMMENTS.ID,
POST_COMMENTS.CONTENT,
POST_COMMENTS.CREATED_AT)
.from(POST_COMMENTS)
.where(POST_COMMENTS.POST_ID.eq(POSTS.ID)))
.as("comments")
.convertFrom(
record3s ->
record3s.into(PostCommentResponse.class)),
records -> records.into(PostCommentResponse.class)),
// Fetch tags as a multiset
multiset(
select(TAGS.NAME)
.from(TAGS)
.join(POSTS_TAGS)
.on(TAGS.ID.eq(POSTS_TAGS.TAG_ID))
.where(POSTS_TAGS.POST_ID.eq(POSTS.ID)))
.as("tags")
.convertFrom(record -> record.map(Record1::value1)))
.from(POSTS.leftJoin(POST_COMMENTS).on(POST_COMMENTS.POST_ID.eq(POSTS.ID)))
.where(where)
.groupBy(POSTS.ID)
.convertFrom(records -> records.map(Record1::value1)))
.from(POSTS)
.where(condition)
.orderBy(getSortFields(pageable.getSort(), POSTS))
.limit(pageable.getPageSize())
.offset(pageable.getOffset());

var countSql = dslContext.selectCount().from(POSTS).where(where);
// Construct the count query
var countQuery = dslContext.selectCount().from(POSTS).where(condition);

// Execute queries reactively and build the result page
return Mono.zip(
Flux.from(dataSql)
Flux.from(dataQuery)
.map(
r ->
record ->
new PostResponse(
r.value1(),
r.value2(),
r.value3(),
r.value4(),
r.value5()))
record.value1(), // Post ID
record.value2(), // Post Title
record.value3(), // Post Content
record.value4(), // Comments
record.value5() // Tags
))
.doOnError(
e ->
log.error(
"Error executing data query: {}",
e.getMessage()))
.collectList(),
Mono.from(countSql).map(Record1::value1))
.map(it -> new PageImpl<>(it.getT1(), pageable, it.getT2()));
Mono.from(countQuery).map(Record1::value1))
.doOnError(e -> log.error("Error executing count query: {}", e.getMessage()))
.map(tuple -> new PageImpl<>(tuple.getT1(), pageable, tuple.getT2()));
}
}
Loading

0 comments on commit aa9cac3

Please sign in to comment.