4

Spring Data Reactive does not support Page as a return type. I'm trying to implement this using two different queries (one to get result list and another to get total count) from Service layer.

The first query gives the contents as Flux<Person> and the second query gives the count as Mono<Integer>.

Can I combine these two and return a Mono<Page<Person>>? How?

Please help.

krishnakumarp
  • 8,967
  • 3
  • 49
  • 55

1 Answers1

2

So finally I coded this as below.

I'm new to this whole reactive paradigm. So the below code may not be the best way to do this. Eventually, I hope Spring Data R2DBC adds support for Page return type. The answer to the above question is in the search method implementation in the CustomMentorRepositoryImpl class.

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Table("mentors")
public class Mentor {

    @Id
    private Long id;
    boolean hasId() {
        return id != null;
    }

    @Version
    @Column("version")
    private Integer version;

    @Column("name")
    private String name;

    @Column("age")
    private Integer age;

}

Repository class

import com.sample.app.domain.Mentor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Repository
public interface MentorRepository extends 
    ReactiveCrudRepository<Mentor, String>, CustomMentorRepository {    
}

// CustomRepository class

import com.sample.app.domain.Mentor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.query.Param;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface CustomMentorRepository {
    public Mono<Page<Mentor>> search(String name, Pageable page);
}

// CustomRepositoryImpl class

import lombok.AllArgsConstructor;
import com.sample.app.domain.Mentor;
import com.sample.app.repository.CustomMentorRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.r2dbc.core.DatabaseClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@AllArgsConstructor
public class CustomMentorRepositoryImpl implements CustomMentorRepository {

    DatabaseClient databaseClient;

    @Override
    public Mono<Page<Mentor>> search(String name, Pageable page) {
        // Get the contents
        Flux<Mentor> contents = databaseClient.execute("SELECT * FROM mentors where name like :name limit :limit offset :offset")
                .bind("name", "%" + name + "%")
                .bind("limit", page.getPageSize())
                .bind("offset", page.getOffset())
                .as(Mentor.class)
                .fetch().all();
        // Get the count
        Mono<Long> count = databaseClient.execute("SELECT count(*) FROM mentors where name like :name")
                .bind("name", "%" + name + "%")
                .as(Long.class)
                .fetch().first();
        return contents.collectList().zipWith(count).flatMap(objects ->
                Mono.just(new PageImpl<Mentor>(objects.getT1(), page, objects.getT2()))
        );
    }
}
krishnakumarp
  • 8,967
  • 3
  • 49
  • 55
  • The official r2dbc doc has an example of PagingAndSortingRepository . Not sure if you can use that. Have you tried it out? – Abhinaba Chakraborty Aug 10 '20 at 12:07
  • PagingAndSortingRepository is not a reactive implementation – krishnakumarp Aug 10 '20 at 13:24
  • 1
    It is really a bad idea of using `Page` in a reactive application, the data in the reactive driven system, it should be live data in the pipe. Returning `Flux`is a good match with ReactiveStreams spec and can apply any operations on the pipe. – Hantsy Sep 09 '20 at 04:22
  • 1
    I replied [the R2dbc pagination](https://stackoverflow.com/questions/58874827/spring-data-r2dbc-and-pagination/63787029#63787029) in this question. – Hantsy Sep 09 '20 at 04:24