
com.github.gkutiel.store.Store Maven / Gradle / Ivy
The newest version!
package com.github.gkutiel.store;
import static java.lang.Integer.MAX_VALUE;
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());
private static final int DEFAULT_MAX_OBJ_SIZE = 1024;
public static Store create(final Class c) {
return create(c, DEFAULT_MAX_OBJ_SIZE);
}
public static Store create(final Class c, final int maxObjSize) {
return new Store<>(c, maxObjSize);
}
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;
@SuppressWarnings("unused")
private Store(final Class c, final int maxObjSize) {
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(maxObjSize);
createIndexes();
}
public int count() {
return count("true");
}
@SuppressWarnings("resource")
public int count(final String where, final Object... args) {
try (Connection con = pool.get()) {
final ResultSet rs = getCount(con, where, args).executeQuery();
rs.next();
return rs.getInt(1);
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
public void del(final String where, final Object... args) {
try (Connection con = pool.get()) {
getDelete(con, where, args).executeUpdate();
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("resource")
public T first(final String where, final Object... args) {
try (Connection con = pool.get()) {
final ResultSet rs = getSelect(con, where, 1, args).executeQuery();
if (!rs.next()) return null;
return GSON.fromJson(rs.getString(1), clazz);
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
public List get() {
return get("true");
}
@SuppressWarnings("resource")
public List get(final String where, final Object... args) {
try (Connection con = pool.get()) {
final List ts = new ArrayList<>();
final ResultSet rs = getSelect(con, where, args).executeQuery();
while (rs.next())
ts.add(GSON.fromJson(rs.getString(1), clazz));
return ts;
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
public void put(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(final int maxObjSize) {
try (Connection con = pool.get()) {
final String table = Temp.table(tableName, indexableFields, getPrimaryKey(clazz), maxObjSize);
LOGGER.fine(table);
con.createStatement().execute(table);
} catch (final SQLException e) {
throw new RuntimeException(e);
}
}
private PreparedStatement getCount(final Connection con, final String cond, final Object... args) {
final PreparedStatement ps = con.prepareStatement("SELECT COUNT(_) FROM " + clazz.getSimpleName() + " WHERE " + cond);
int i = 1;
for (final Object v : args)
Utils.set(ps, i++, v);
return ps;
}
private String getCreateIndex(final Field field) {
final String createIndex = "CREATE INDEX IF NOT EXISTS " + field.getName() + " ON " + tableName + "(" + field.getName() + ")";
LOGGER.fine(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)
Utils.set(ps, i++, v);
LOGGER.fine(ps.toString());
return ps;
}
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)
Utils.set(ps, ++i, field.get(t));
LOGGER.fine(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 int limit, final Object... args) {
final PreparedStatement ps = con.prepareStatement("SELECT _ FROM " + clazz.getSimpleName() + " WHERE " + cond + " LIMIT " + limit);
int i = 1;
for (final Object v : args)
Utils.set(ps, i++, v);
return ps;
}
private PreparedStatement getSelect(final Connection con, final String cond, final Object... args) {
return getSelect(con, cond, MAX_VALUE, args);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy