Skip to content

ninjaframework/ninja-db

Repository files navigation

 _______  .___ _______        ____.  _____   
 \      \ |   |\      \      |    | /  _  \  
 /   |   \|   |/   |   \     |    |/  /_\  \
/    |    \   /    |    \/\__|    /    |    \
\____|__  /___\____|__  /\________\____|__  /
     web\/framework   \/                  \/

Finest relational database support for Ninja

  • Continuous integration: Build Status

This project allows Ninja applications to access relational databases.

It is based on three building blocks:

  • Migration support via the popular flyway library
  • Fast jdbc access via Hikari connection pool
  • Support for many jdbc libraries like jdbi and many more

Note: Ninja-db is designed to be extensible. Currently we only support jdbi. But it is straight forward to add JPA, ebean or any other relational access framework. PRs welcome!

Quickstart with JDBI

Check out ninja-db-jdbi-demo for a working configuration. If you want to add everything manually do the following:

Add the following dependencies for migrations and access via jdbi.

<dependency>
    <groupId>org.ninjaframework</groupId>
    <artifactId>ninja-db-jdbi</artifactId>
    <version>NINJA_DB_VERSION</version>
</dependency>

<dependency>
    <groupId>org.ninjaframework</groupId>
    <artifactId>ninja-db-flyway</artifactId>
    <version>NINJA_DB_VERSION</version>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.199</version>
</dependency>

Note: Instead of h2database you can of course any other database you like (postgresql etc).

Then activate the dependencies in your Module.java file:

public class Module extends AbstractModule {

    protected void configure() {
        install(new NinjaFlyway());
        install(new NinjaJdbiModule());
    }

}

Finally configure your datasource in the application.conf file:

application.datasource.default.driver=org.h2.Driver
application.datasource.default.url=jdbc:h2:mem:test
application.datasource.default.username=sa
application.datasource.default.password=

application.datasource.default.migration.enabled=true
application.datasource.default.migration.username=sa
application.datasource.default.migration.password=

# Hikari can be configured on each datasource.
# Parameters are extracted and provided to hikari.
# Please refer to the hikari config for all parameters 
# https://github.com/brettwooldridge/HikariCP
application.datasource.default.hikari.idleTimeout=10000
application.datasource.default.hikari.maxLifetime=10000
application.datasource.default.hikari.maximumPoolSize=10

Accessing the database is then simply a matter of injecting NinjaJdbi. In case of JDBI a good way is having an interface with annotated SQL queries and a service (GuestbooksService) that uses it and can itself be injected into your controller.

The service:

import com.google.inject.Inject;
import java.util.List;
import models.Guestbook;
import ninja.jdbi.NinjaJdbi;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.customizer.BindBean;

import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import org.jdbi.v3.sqlobject.statement.UseRowMapper;


public class GuestbooksService {
    
    public interface DbServiceInterface {  
        @SqlQuery("SELECT id, email, content FROM guestbooks")
        @UseRowMapper(Guestbook.GuestbookMapper.class)
        List<Guestbook> listGuestBookEntries();
        
        @SqlUpdate("INSERT INTO guestbooks (email, content) VALUES (:email, :content)")
        void createGuestbook(@BindBean Guestbook guestbook);
    }

    private final Jdbi jdbi;
            
    @Inject     
    public GuestbooksService(NinjaJdbi ninjaJdbi) {
        this.jdbi = ninjaJdbi.getJdbi("default");
    }

    public List<Guestbook> listGuestBookEntries() {
        return jdbi.open().attach(DbServiceInterface.class).listGuestBookEntries();
    }

    public void createGuestbook(Guestbook guestbook) {
        jdbi.open().attach(DbServiceInterface.class).createGuestbook(guestbook);
    }
    
}

and the Controller then'd look like:

@Inject
public ApplicationController(Lang lang,
                             Logger logger,
                             GuestbooksService dbService) {
    this.lang = lang;
    this.logger = logger;
    this.dbService = dbService;

}

public Result index() {

    // Get all guestbookentries now:
    List<Guestbook> guestBookEntries = dbService.listGuestBookEntries();

    Map<String, Object> toRender = Maps.newHashMap();
    toRender.put("guestBookEntries", guestBookEntries);

    // Default rendering is simple by convention
    // This renders the page in views/ApplicationController/index.ftl.html
    return Results.html().render(toRender);

}

Releasing (committers only)

Make sure you got gpg installed on your machine. Gpg is as good as gpg2, so there's not much difference. But the gpg plugin in maven works better with gpg, so we go with that one

brew install gpg

Make sure to create a key

gpg --gen-key

Then list the keys and send the public key to a keyserver so that people can verify that it's you:

gpg --keyserver hkp://pool.sks-keyservers.net --send-keys YOUR_PUBLIC_KEY

Make sure to set

export GPG_TTY=$(tty)

... that way any input of gpg will be properly shown (entering your passphrase for instance)...

Make sure you set the sonatype credentials in your ~/.m2/settings.xml:

<settings>

  <servers>
    <server>
      <id>ossrh</id>
      <username>USERNAME</username>
      <password>PASSWORD</password>
    </server>
  </servers>

</settings>

Then you can create a new release like so:

mvn release:clean -Prelease
mvn release:prepare -Prelease
mvn release:perform -Prelease