com.github.gkutiel.store.Store Maven / Gradle / Ivy
package com.github.gkutiel.store;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.h2.Driver;
import com.github.gkutiel.store.ConnectionPool.Connection;
import com.google.gson.Gson;
public class Store {
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public static @interface Index {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public static @interface Key {
String[] value();
}
private static final Gson GSON = new Gson();
private static final Logger LOGGER = Logger.getLogger(Store.class.getCanonicalName());
public static Store create(final Class c) {
return new Store<>(c);
}
private static List getIndexableFields(final Class> c) {
final List indexedFields = new ArrayList<>();
final Field[] declaredFields = c.getDeclaredFields();
AccessibleObject.setAccessible(declaredFields, true);
for (final Field field : declaredFields)
if (field.isAnnotationPresent(Index.class)) indexedFields.add(field);
return indexedFields;
}
private final ConnectionPool pool;
private final Class clazz;
private final List indexableFields;
private final String tableName;
private final String insert;
private final String delete;
private Store(final Class c) {
this.clazz = c;
new Driver();
indexableFields = getIndexableFields(c);
tableName = clazz.getSimpleName();
insert = Temp.insert(clazz.isAnnotationPresent(Key.class), tableName, indexableFields.size());
delete = "DELETE FROM " + tableName + " WHERE ";
pool = new ConnectionPool("jdbc:h2:db/store");
createTable();
createIndexes();
}
public void add(final T t) {
try (Connection con = pool.get()) {
getInsertStmt(con, t).executeUpdate();
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
private void createIndex(final Connection con, final Field field) {
try {
con.prepareStatement(getCreateIndex(field)).execute();
} catch (final SQLException e) {
throw new RuntimeException();
}
}
private void createIndexes() {
try (Connection con = pool.get()) {
for (final Field field : indexableFields)
createIndex(con, field);
}
}
private void createTable() {
try (Connection con = pool.get()) {
final String table = Temp.table(clazz, indexableFields, getPrimaryKey(clazz));
LOGGER.info(table);
con.createStatement().execute(table);
} catch (final SQLException e) {
throw new RuntimeException();
}
}
public void delIf(final String cond, final Object... args) {
try (Connection con = pool.get()) {
getDelete(con, cond, args).executeUpdate();
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
public List getAll() {
return getIf("true");
}
private String getCreateIndex(final Field field) {
final String createIndex = "CREATE INDEX IF NOT EXISTS " + field.getName() + " ON " + tableName + "(" + field.getName() + ")";
LOGGER.info(createIndex);
return createIndex;
}
private PreparedStatement getDelete(final Connection con, final String cond, final Object... args) {
final PreparedStatement ps = con.prepareStatement(delete + cond);
int i = 1;
for (final Object v : args)
Statement.set(ps, i++, v);
LOGGER.info(ps.toString());
return ps;
}
public List getIf(final String cond, final Object... args) {
try (Connection con = pool.get()) {
final List ts = new ArrayList<>();
final ResultSet rs = getSelect(con, cond, args).executeQuery();
while (rs.next())
ts.add(GSON.fromJson(rs.getString(1), clazz));
return ts;
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
private PreparedStatement getInsertStmt(final Connection con, final T t) throws IllegalAccessException, SQLException {
final PreparedStatement ps = con.prepareStatement(insert);
int i = 1;
ps.setString(i, GSON.toJson(t));
for (final Field field : indexableFields)
Statement.set(ps, ++i, field.get(t));
LOGGER.info(ps.toString());
return ps;
}
private String[] getPrimaryKey(final Class c) {
if (c.isAnnotationPresent(Key.class)) return c.getAnnotation(Key.class).value();
return null;
}
private PreparedStatement getSelect(final Connection con, final String cond, final Object... args) {
final PreparedStatement ps = con.prepareStatement("SELECT obj FROM " + clazz.getSimpleName() + " WHERE " + cond);
int i = 1;
for (final Object v : args)
Statement.set(ps, i++, v);
return ps;
}
}