infobip-spring-data-querydsl icon indicating copy to clipboard operation
infobip-spring-data-querydsl copied to clipboard

someway to define my own repository

Open Peak-Song opened this issue 1 year ago • 2 comments

Thanks for your amazing project, I feels exceptionally smooth when using r2dbc and querydsl, so I strongly recommend it to my colleagues. However, I have a small question I'd like to ask you.

I want to extend the origin Repository to implement my own Repository, such as ReactivePagingRepository below.

package com.it.gm.cube.app.base

import com.it.gm.cube.bdpc.common.PageResult
import com.it.gm.cube.bdpc.common.PageVo
import com.querydsl.core.types.OrderSpecifier
import com.querydsl.core.types.Predicate
import com.querydsl.sql.RelationalPathBase
import org.springframework.data.repository.NoRepositoryBean
import org.springframework.data.repository.Repository
import reactor.core.publisher.Mono

@NoRepositoryBean
interface ReactivePagingRepository<T, ID>: Repository<T, ID> {

    fun <T> simplePaging(
        pageVo: PageVo,
        count: Long,
        table: RelationalPathBase<T>,
        predication: Predicate,
        orderBy: OrderSpecifier<String>
    ): Mono<PageResult<T>>
}

And Then implement the interface with

package com.it.gm.cube.app.base

import com.infobip.spring.data.r2dbc.QuerydslR2dbcFragment
import com.it.gm.cube.bdpc.common.PageResult
import com.it.gm.cube.bdpc.common.PageVo
import com.it.gm.cube.bdpc.common.PagingUtil
import com.querydsl.core.types.OrderSpecifier
import com.querydsl.core.types.Predicate
import com.querydsl.sql.RelationalPathBase
import org.springframework.context.ApplicationContext
import org.springframework.stereotype.Component
import reactor.core.publisher.Mono

@Component
class ReactivePagingRepositoryBean<T, ID>(private val context: ApplicationContext) :
    ReactivePagingRepository<T, ID> {

    override fun <T> simplePaging(
        pageVo: PageVo,
        count: Long,
        table: RelationalPathBase<T>,
        predication: Predicate,
        orderBy: OrderSpecifier<String>
    ): Mono<PageResult<T>> {

        val bean = context.getBean(QuerydslR2dbcFragment::class.java)

        return if (count == 0L)
            Mono.just(PageResult<T>(0, listOf<T>(), 1))
        else {
            val pagingInfo = PagingUtil.limitOffset(pageVo, count)
            bean.query { query ->
                query.select(table).from(table).where(predication)
                    .orderBy(orderBy)
                    .limit(pagingInfo.limit).offset(pagingInfo.offset)
            }.all().collectList().map { PageResult<T>(count, it as List<T>, pagingInfo.currentPage) }
        }

    }
}

Finally, I use it like this


@Configuration
@EnableR2dbcRepositories(repositoryBaseClass = ReactivePagingRepositoryBean::class)
class DbConfiguration {

    private val log by LoggerDelegate()

    @Bean
    fun sqlTemplates(): SQLTemplates {
        return APostgreSQLTemplates()
    }

}

@NoRepositoryBean
interface QuerydslRepository<T, ID> : ReactiveSortingRepository<T, ID>, ReactiveCrudRepository<T, ID>,
    ReactiveQuerydslPredicateExecutor<T>, ReactivePagingRepository<T, ID>, QuerydslR2dbcFragment<T>

@Configuration
@EnableR2dbcRepositories(repositoryBaseClass = ReactivePagingRepositoryBean::class)
class DbConfiguration {}

interface ApiTreeRepository: QuerydslRepository<ApiTree, Long>

But it raise exception whrn project start. Caused by: org.springframework.data.mapping.PropertyReferenceException: No property 'simplePaging' found for type 'ApiTree'

there is the project dependency I use -- springboot3.3.3 and

    implementation("org.postgresql:r2dbc-postgresql:1.0.5.RELEASE")
    implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
    implementation("com.infobip:infobip-spring-data-r2dbc-querydsl-boot-starter:9.0.7")
    compileOnly("com.infobip:infobip-spring-data-jdbc-annotation-processor:9.0.7")
    kapt("com.infobip:infobip-spring-data-jdbc-annotation-processor:9.0.7")

Is there Anyway to achieve this feature? Please tell me, thanks a lot~

Peak-Song avatar Oct 21 '24 03:10 Peak-Song

Hi, thank you for your kind words. I'd suggest using the fragment (custom repository approach) - https://docs.spring.io/spring-data/jpa/reference/repositories/custom-implementations.html

public interface ReactivePagingRepository<T> {

    Mono<T> simplePaging(String string);
}
import org.springframework.context.annotation.Lazy;
import reactor.core.publisher.Mono;

public class ReactivePagingRepositoryImpl<T> implements ReactivePagingRepository<T> {

    private final QuerydslR2dbcFragment querydslR2dbcFragment;

    public ReactivePagingRepositoryImpl(@Lazy QuerydslR2dbcFragment querydslR2dbcFragment) {
        this.querydslR2dbcFragment = querydslR2dbcFragment;
    }

    @Override
    public Mono<T> simplePaging(... parameters) {
        ... implementation
    }
}

This is implementation side, on use side you need to do something like

public interface PersonRepository extends QuerydslR2dbcRepository<Person, Long>, ReactivePagingRepository<Person> {
}

You can of course introduce another abstract interface that extends QuerydslR2dbcRepository<T, ID>, ReactivePagingRepository<T> like QuerydslR2dbcRepository does so your concrete repositories doesn't have to extend both but this approach is arbitrary. To keep the repository implementation clean I'd suggest keeping the repository hierarchies as separate as possible.

lpandzic avatar Oct 21 '24 06:10 lpandzic

it doesn't work for me, the same exception info raised

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cubeTagFactoryController' defined in file [D:\Project\datacube-platform-bdpc\build\classes\kotlin\main\com\it\gm\cube\bdpc\cube\CubeTagFactoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'tagFactoryService' defined in file [D:\Project\datacube-platform-bdpc\build\classes\kotlin\main\com\it\gm\cube\bdpc\cube\service\TagFactoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'tagFactoryRepository' defined in com.it.gm.cube.bdpc.cube.repository.TagFactoryRepository defined in @EnableR2dbcRepositories declared on QuerydslR2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:237) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1212) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.12.jar:6.1.12]
.......
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tagFactoryService' defined in file [D:\Project\datacube-platform-bdpc\build\classes\kotlin\main\com\it\gm\cube\bdpc\cube\service\TagFactoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'tagFactoryRepository' defined in com.it.gm.cube.bdpc.cube.repository.TagFactoryRepository defined in @EnableR2dbcRepositories declared on QuerydslR2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:237) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1212) ~[spring-beans-6.1.12.jar:6.1.12]
........ 19 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tagFactoryRepository' defined in com.it.gm.cube.bdpc.cube.repository.TagFactoryRepository defined in @EnableR2dbcRepositories declared on QuerydslR2dbcRepositoriesAutoConfigureRegistrar.EnableR2dbcRepositoriesConfiguration: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.12.jar:6.1.12]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.12.jar:6.1.12]
....... 19 more
Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); Reason: Failed to create query for method public abstract reactor.core.publisher.Mono com.it.gm.cube.app.base.ReactivePagingRepository.simplePaging(com.it.gm.cube.bdpc.common.PageVo,long,com.querydsl.sql.RelationalPathBase,com.querydsl.core.types.Predicate,com.querydsl.core.types.OrderSpecifier); No property 'simplePaging' found for type 'CubeTag'
        at org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:119) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:103) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:92) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at java.base/java.util.Optional.map(Optional.java:260) ~[?:?]
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:92) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:357) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:286) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at org.springframework.data.util.Lazy.getNullable(Lazy.java:135) ~[spring-data-commons-3.3.3.jar:3.3.3]
        at org.springframework.data.util.Lazy.get(Lazy.java:113) ~[spring-data-commons-3.3.3.jar:3.3.3]

        ... 19 more

Peak-Song avatar Oct 22 '24 03:10 Peak-Song

Check out https://github.com/infobip/infobip-spring-data-querydsl/blob/issue-105-example/infobip-spring-data-r2dbc-custom-fragment/src/test/java/com/infobip/test/QuerydslR2dbcRepositoryTest.java It should fail with https://github.com/infobip/infobip-spring-data-querydsl/blob/issue-105-example/infobip-spring-data-r2dbc-custom-fragment/src/test/java/com/infobip/test/ReactivePagingRepositoryImpl.java#L17 (you can put a breakpoint there and debug).

lpandzic avatar Oct 31 '24 06:10 lpandzic