10

is there pagination support for custom queries in SDN4?

  • If yes, how does it work?
  • If no, is there a workarround?

I have the following Spring Data Neo4j 4 repository:

@Repository
public interface TopicRepository 
  extends GraphRepository<Topic>,IAuthorityLookup {

  // other methods omitted
  @Query("MATCH (t:Topic)-[:HAS_OFFICER]->(u:User) "
    + "WHERE t.id = {0} "
    + "RETURN  u")
  public Page<User> topicOfficers(Long topicId, Pageable pageable);
}

And the corresponding testcase:

@Test
public void itShouldReturnAllOfficersAsAPage() {
  Pageable pageable = new PageRequest(1,10);
  Page<User> officers = topicRepository.topicOfficers(1L, pageable);
  assertNotNull(officers);
}

When I run the test, I run into the following exception

Failed to convert from type java.util.ArrayList<?> to type   org.springframework.data.domain.Page<?> for value '[org.lecture.model.User@1]'; 
nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type java.util.ArrayList<?> to type org.springframework.data.domain.Page<?>

This is my setup:

dependencies {
//other dependencies omitted
  compile("org.neo4j:neo4j-cypher-dsl:2.0.1")


  compile "org.neo4j.app:neo4j-server:2.2.2"

  compile(group: 'org.springframework.data',
          name: 'spring-data-neo4j',
          version: '4.0.0.BUILD-SNAPSHOT')


  compile(group: 'org.springframework.data',
          name: 'spring-data-neo4j',
          version: '4.0.0.BUILD-SNAPSHOT',
          classifier: 'tests')

  testCompile(group: 'org.neo4j',
          name: 'neo4j-kernel',
          version: '2.2.2',
          classifier: 'tests')

  testCompile(group: 'org.neo4j.app',
              name: 'neo4j-server',
              version: '2.2.2',
              classifier: 'tests')

  testCompile(group: 'org.neo4j',
              name: 'neo4j-io',
              version: '2.2.2',
              classifier: 'tests')
} 

The Snapshot I use should able to handle pagination, since the following test runs just fine:

@Test
public void itShouldReturnAllTopicsAsAPage() {

  Pageable pageable = new PageRequest(1,10);
  Page<Topic> topics = topicRepository.findAll(pageable);

  assertNotNull(topics);
}
ShrimpPhaser
  • 3,257
  • 1
  • 23
  • 22

3 Answers3

6

This is now allowed using Sort or Pageable interfaces in your query, and was fixed in DATAGRAPH-653 and marked as fixed in version 4.2.0.M1 (currently in pre-release).

Queries such as the following are possible:

@Query("MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor")
List<Actor> getActorsThatActInMovieFromTitle(String movieTitle, Sort sort);

and:

@Query("MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor")
Page<Actor> getActorsThatActInMovieFromTitle(String movieTitle, PageRequest page);

(sample from Cypher Examples in the Spring Data + Neo4j docs)

Finding Spring Data Neo4j Pre-Release Milestone Builds:

You can view the dependencies information for any release on the project page. And for the 4.2.0.M1 build the information for Gradle (you can infer Maven) is:

dependencies {
    compile 'org.springframework.data:spring-data-neo4j:4.2.0.M1'
}

repositories {
    maven {
        url 'https://repo.spring.io/libs-milestone'
    }
}

Any newer final release should be used instead.

Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
4

At the moment this isn't possible.

To enable this feature we'd need to do a few things. First at startup we would need to inspect the query's associated method signature and mark the query as requiring paging. Then at runtime when the method was invoked we'd need to obtain the pageable instance, extract the page parameters and apply them as SKIP and LIMIT clauses to the associated Cypher query. Finally, on return, we'd need wrap the results in a Page object. So there's a bit of work to be done to enable this.

In the meantime you could try adding the SKIP and LIMIT clauses with parameterised values to the query, and pass the appropriate values in via to the query method. I haven't tried this, but it should work - in theory:

  @Query("MATCH (t:Topic)-[:HAS_OFFICER]->(u:User) "
+ "WHERE t.id = {0} "
+ "RETURN  u SKIP {1} LIMIT {2}" )
public List<User> topicOfficers(long topicId, long skip, long limit)
Vince
  • 2,181
  • 13
  • 16
  • Thank you for your reply! I have one question since you have more insight than me on SDN4... is this a feature that (if at all) will be avaiable in the foreseeable future? Let's say, the RC of SDN4. This information would help me a lot to make a decission on whether or not to rewrite my api. – ShrimpPhaser Jun 03 '15 at 17:47
  • It won't be available in the first RC because that's in code-freeze right now. I've created a ticket for it, and added it to to the backlog for the following release. At the moment I can't say when that will be. https://jira.spring.io/browse/DATAGRAPH-653 – Vince Jun 03 '15 at 18:05
  • @Vince For our system we need the getTotalPages(), isFirst() and isLast() values from the Page returned by performing a custom paging query. Are you able to provide any recommendations on how to do this / is there SDN code you can point me to that does the construction of the Page object? Thanks – Coder Shark Aug 13 '15 at 11:03
  • please see my answer here: http://stackoverflow.com/questions/32011358/sdn4-custom-query-pagination-alternative-for-page-contents/32013946#32013946 – Vince Aug 14 '15 at 15:53
  • I'v just resolved this issue with adding countQuery to @Query annotation. Example: @Query(value = "MATCH (t:Topic)-[:HAS_OFFICER]->(u:User) WHERE t.id = {0} RETURN u", countQuery = "MATCH (t:Topic)-[:HAS_OFFICER]->(u:User) WHERE t.id = {0} RETURN count(u)") – Marian Jun 16 '16 at 09:40
1

As a follow-up to @Jayson Minard's answer, more recent versions of Spring Data Neo4j (6.0.7+) requires a count query attached with the regular one to return a Page object, such as :

@Query(value = "MATCH (t:Topic)-[:HAS_OFFICER]->(u:User) WHERE t.id = {0} "
             + "RETURN u SKIP $skip LIMIT $limit",
        countQuery = "MATCH (t:Topic)-[:HAS_OFFICER]->(u:User) WHERE t.id = {0} "
             + "RETURN count(u)")
public Page<User> topicOfficers(Long topicId, Pageable pageable);
Robin
  • 1,438
  • 2
  • 19
  • 29