# Data Persistence

This page explains how to integrate Jiny with databases such as MySQL/MSSQL or MongoDB

# SQL Databases

First, install SQL driver dependency:

build.gradle

// Can be SQLite or H2 ...
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.49'

Next, create an SQL initial (get connection) methods:

public final class MySQLUtils {
    public static Connection init() {
        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance(); // Can be SQLite or H2 ...
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        try {
            // Can be SQLite or H2 ...
            return DriverManager.getConnection("jdbc:mysql://localhost/test?user=root&password=example");
        } catch (SQLException t) {
            log.error(t.getMessage(), t);
        }

        return null;
    }
}

Then use that connection to do queries:

public HttpResponse getDogs(Context ctx) throws SQLException {
    @Cleanup val stmt = conn.prepareStatement("SELECT * FROM dog");
    @Cleanup val rs = stmt.executeQuery();
    val dogs = new ArrayList<Dog>();
    while (rs.next()) {
        val id = rs.getInt("id");
        val name = (String) rs.getObject("name");
        val owner = (String) rs.getObject("owner");
        val dog = new Dog(id, name, owner);
        dogs.add(dog);
    }
    return HttpResponse.of(dogs);
}

# Hibernate ORM

First, install the MySQL and Hibernate dependencies:

build.gradle

compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.49'
compile group: 'org.hibernate', name: 'hibernate-core', version: '5.3.6.Final'

Create Hibernate Factory:

@Setter
public class HibernateFactory {
    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            val configuration = new Configuration();
            configuration.setProperty("hibernate.current_session_context_class", "thread");
            configuration.setProperty("connection.driver_class", "com.mysql.jdbc.Driver");
            configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");
            configuration.setProperty("hibernate.connection.username", "root");
            configuration.setProperty("hibernate.connection.password", "example");
            configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
            configuration.setProperty("hibernate.hbm2ddl.auto", "update");
            configuration.setProperty("show_sql", "true");
            configuration.setProperty("hibernate.connection.pool_size", "10");
            configuration.addAnnotatedClass(Tiger.class);
            val builder = new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties());
            sessionFactory = configuration.buildSessionFactory(builder.build());
        }

        return sessionFactory;
    }
}

Create an entity and use persistence annotations:

@Data
@Entity
public class Tiger {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
    String name;
    String owner;
}

Then, create base repositories, example CrudRepository:

@RequiredArgsConstructor
public abstract class CrudRepository<T> {
    private final SessionFactory sessionFactory;
    private final Class<T> entityClass;

    public T save(T entity) {
        val session = sessionFactory.getCurrentSession();
        val tx = session.beginTransaction();
        session.save(entity);
        tx.commit();
        return entity;
    }

    public T find(long id) {
        val session = sessionFactory.getCurrentSession();
        val tx = session.beginTransaction();
        try {
            return session.find(entityClass, id);
        } finally {
            tx.commit();
        }
    }

    public void update(T entity) {
        val session = sessionFactory.getCurrentSession();
        val tx = session.beginTransaction();
        sessionFactory.getCurrentSession().update(entity);
        tx.commit();
    }

    public void delete(T entity) {
        val session = sessionFactory.getCurrentSession();
        val tx = session.beginTransaction();
        session.delete(entity);
        tx.commit();
    }

    public List<T> list() {
        val session = sessionFactory.getCurrentSession();
        val tx = session.beginTransaction();
        try {
            CriteriaQuery<T> query = session.getCriteriaBuilder().createQuery(entityClass);
            query.select(query.from(entityClass));
            return session.createQuery(query).getResultList();
        } finally {
            tx.commit();
        }
    }
}

Define an entity's repository:

public class TigerRepository extends CrudRepository<Tiger> {}

And finally use it in handlers:

public class TigerHandler {
    private final Gson gson = AppFactory.getGson();
    private final TigerRepository tigerRepository = RepositoryFactory.getTigerRepository();

    public HttpResponse getTigers(Context ctx) {
        return HttpResponse.of(tigerRepository.list());
    }

    public HttpResponse getTiger(Context ctx) {
        val id = Integer.parseInt(ctx.pathParam("id"));
        return HttpResponse.of(tigerRepository.find(id));
    }

    public HttpResponse addTiger(Context ctx) {
        val body = ctx.getBody();
        val newTiger = gson.fromJson(body, Tiger.class);
        val added = tigerRepository.save(newTiger);
        return HttpResponse.of(added);
    }
}

# Mongo Database

First, install the MongoDB driver dependency:

build.gradle

compile group: 'org.mongodb', name: 'mongodb-driver-sync', version: '4.1.0-beta2'

Next, create a MongoDB initial (get connection) methods:

public final class MongoDBUtils {
    public static MongoClient init() {
        CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
                fromProviders(PojoCodecProvider.builder().automatic(true).build()));

        // Use MongoDB POJO Mapping feature, the driver will convert POJO to MongoDB query result internally
        MongoClientSettings settings = MongoClientSettings.builder()
                .codecRegistry(pojoCodecRegistry)
                .build();

        return MongoClients.create(settings);
    }
}

Then use that connection to do queries:

public HttpResponse getCats(Context ctx) {
    val catArr = new ArrayList<Cat>();
    catCollection.find().forEach(catArr::add);
    return HttpResponse.of(catArr.toArray());
}