1

A very basic question from a newbie to the wonderful jhipster ecosystem.

How do I add an additional page to my app that displays two plots based on queries on the database?

I have created the demo jhipster app that tracks authors and books in a postgres database as described in the tutorial.

I would now like to add a summary page to my sample jhipster app that displays two plots based on data retrieved from an sql query.

1) barplot of total books published per author

 select author_id, count(*)
 from book
 group by author_id 

2) line plot showing number of publications for each author per year

select author_id,extract(year from publication_date) as year,count(*)
from book
group by author_id,year

I would normally use R/Shiny and plotly to create this type of dashboard, but would really appreciate any guidance on how to achieve the same using the jhipster framework

Thanks

Iain

Iain
  • 1,608
  • 4
  • 22
  • 27

2 Answers2

2

I see 2 tasks here. In general you first prepare 2 API endpoints to deliver the data to your frontend (keep in mind, JHI provides both server and client), and then using plotly (js) to do your plots

preparing API

you should translate your SQL query to JPA, like this:

public interface BookRepository extends JpaRepository<Book,Long> {
  @Query("select b.authorId, count(b.id) from Book b  group by b.authorId ")
  List<Book> findAllGroupByAuthor();

  @Query("select b.authorId, YEAR(b.publicationDate) as year,count(*) from Book b group by b.authorId, b.year")
  List<Book> findAllGroupByAuthorAndYear();
}

then you add this to some RestControllers. Here is an example

@RestController
@RequestMapping("/api/books/query/")
public class CustomBookQueryResource {

  private BookRepository bookRepository;

  public CustomBookQueryResource(BookRepository bookRepository) {
    this.bookRepository = bookRepository;
  }

  @GetMapping("/group_by_author")
  public ResponseEntity<List<Book>> groupByAuthor() {
    return ResponseEntity.ok(bookRepository.findAllGroupByAuthor());
  }

  @GetMapping("/group_by_author_and_year")
  public ResponseEntity<List<Book>> groupByAuthorAndYear() {
    return ResponseEntity.ok(bookRepository.findAllGroupByAuthorAndYear());
  }
}

so until this point, you should already have some api endpoints, serving your data. Now you should add your custom query book service in angular

angular
    .module('<yourApp>')
    .factory('CustomBookQuery', CustomBookQuery);

CustomBookQuery.$inject = ['$http'];
function CustomBookQuery ($http) {
    var resourceUrl =  'api/books/query/';

    return {
      findAllGroupByAuthor: function () {
        return $http.get(resourceUrl + 'group_by_author');
      },
      findAllGroupByAuthorAndYear: function () {
        return $http.get(resourceUrl + 'group_by_author_and_year');
      }
    };
}

Now you just can inject your service and pass its promises resolves to your plotly, which is already has and JS part and a Angular implementation

(I coded above code from mind, so it's not tested)

David Steiman
  • 3,055
  • 2
  • 16
  • 22
  • Thanks - that should help me get started, but if you were so inclined it would be great if you could update your code with working example for the rest end point. I haven't been able to figure it out. – Iain Jan 18 '17 at 01:41
  • what exactly is the problem with it? – David Steiman Jan 18 '17 at 10:59
1

For simple cases where your query only involves one entity it might be as simple as adding a method or methods to the associated Repository interface and have Spring Data handle the query generation.

Take a look at https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation

and if you'd prefer to supply the query

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query

You could then add an HTML page with JS to render the plot of the results of the query.

For situations that require a join over entities there’s a few possible approaches…

You could create a view in PostGresQL that would effectively make a table which is this query and then create an Entity for it (and then render them in your fav JS lib). This is my preferred option. You would need to update the liquidbase file to create the view. You would make an Entity and you would create a Spring Data repository interface (which will result in the autogeneration of a REST service etc) and then render using HTML and JS.

Alternatively, JPA entities can be queries using JPQL. That will give you a collection of objects that you can render with Angular.js or whatever your fav JS library.

http://www.oracle.com/technetwork/articles/vasiliev-jpql-087123.html

You can also use JPA to map native SQL to a PoJo (see especially the JPA 2.1 notes) and then create a REST service and render using your JS.

JPA : How to convert a native query result set to POJO class collection http://www.thoughts-on-java.org/jpa-native-queries/

Community
  • 1
  • 1
Mark
  • 2,260
  • 18
  • 27