package in.partake.model.dao.postgres9; import in.partake.base.DateTime; import in.partake.base.TimeUtil; import in.partake.model.dao.DAOException; import in.partake.model.dao.DataIterator; import in.partake.model.dao.DataMapper; import java.io.ByteArrayInputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; import java.util.UUID; /** * * @author shinyak * */ public class Postgres9EntityDao extends Postgres9Dao { private final String tableName; public Postgres9EntityDao(String tableName) { this.tableName = tableName; } public void initialize(Postgres9Connection con) throws DAOException { makeSureExistEntitiesTable(con); } private void makeSureExistEntitiesTable(Postgres9Connection con) throws DAOException { try { if (existsTable(con, tableName)) return; createEntitiesTable(con.getConnection()); } catch (SQLException e) { throw new DAOException(e); } } private void createEntitiesTable(Connection con) throws SQLException { // NOTE: Postgres9.1 has 'CREATE TABLE IF NOT EXISTS' though postgres9.0 does not have it. PreparedStatement ps = null; try { ps = con.prepareStatement( "CREATE TABLE " + tableName + "(" + " id UUID PRIMARY KEY," + " version INTEGER NOT NULL," + " body BYTEA NOT NULL," + " opt BYTEA," + " updatedAt TIMESTAMP NOT NULL" + ")"); ps.execute(); } finally { close(ps); } } public String getFreshId(Postgres9Connection con) throws DAOException { for (int i = 0; i < 5; ++i) { UUID uuid = UUID.randomUUID(); if (!exists(con, uuid.toString())) return uuid.toString(); } return null; } public void insert(Postgres9Connection pcon, Postgres9Entity entity) throws DAOException { Connection con = pcon.getConnection(); PreparedStatement ps = null; try { ps = con.prepareStatement("INSERT INTO " + tableName + "(id, version, body, opt, updatedAt) VALUES(?, ?, ?, ?, ?)"); ps.setObject(1, entity.getId(), Types.OTHER); ps.setInt(2, entity.getVersion()); ps.setBinaryStream(3, new ByteArrayInputStream(entity.getBody()), entity.getBodyLength()); if (entity.getOpt() != null) ps.setBinaryStream(4, new ByteArrayInputStream(entity.getOpt()), entity.getOptLength()); else ps.setNull(4, Types.NULL); ps.setTimestamp(5, new Timestamp(entity.getUpdatedAt().getTime())); ps.execute(); } catch (SQLException e) { throw new DAOException(e); } finally { close(ps); } } public void update(Postgres9Connection pcon, Postgres9Entity entity) throws DAOException { Connection con = pcon.getConnection(); PreparedStatement ps = null; try { ps = con.prepareStatement("UPDATE " + tableName + " SET version = ?, body = ?, opt = ?, updatedAt = ? WHERE id = ?"); ps.setInt(1, entity.getVersion()); ps.setBinaryStream(2, new ByteArrayInputStream(entity.getBody()), entity.getBodyLength()); if (entity.getOpt() != null) ps.setBinaryStream(3, new ByteArrayInputStream(entity.getOpt()), entity.getOptLength()); else ps.setNull(3, Types.NULL); ps.setTimestamp(4, new Timestamp(TimeUtil.getCurrentTime())); ps.setObject(5, entity.getId(), Types.OTHER); ps.execute(); } catch (SQLException e) { throw new DAOException(e); } finally { close(ps); } } public boolean exists(Postgres9Connection pcon, UUID id) throws DAOException { return exists(pcon, id.toString()); } public boolean exists(Postgres9Connection pcon, String id) throws DAOException { Connection con = pcon.getConnection(); PreparedStatement ps = null; ResultSet rs = null; try { ps = con.prepareStatement("SELECT 1 FROM " + tableName + " WHERE id = ?"); ps.setObject(1, id, Types.OTHER); rs = ps.executeQuery(); return rs.next(); } catch (SQLException e) { throw new DAOException(e); } finally { close(rs); close(ps); } } public Postgres9Entity find(Postgres9Connection pcon, String id) throws DAOException { Connection con = pcon.getConnection(); PreparedStatement ps = null; ResultSet rs = null; try { ps = con.prepareStatement("SELECT version, body, opt, updatedAt FROM " + tableName + " WHERE id = ?"); ps.setObject(1, id, Types.OTHER); rs = ps.executeQuery(); if (rs.next()) { int version = rs.getInt(1); byte[] body = rs.getBytes(2); byte[] opt = rs.getBytes(3); Timestamp updatedAt = rs.getTimestamp(4); return new Postgres9Entity(id, version, body, opt, updatedAt != null ? new DateTime(updatedAt.getTime()) : null); } else { return null; } } catch (SQLException e) { throw new DAOException(e); } finally { close(rs); close(ps); } } public Postgres9Entity find(Postgres9Connection pcon, UUID id) throws DAOException { return find(pcon, id.toString()); } /** Removes */ public void remove(Postgres9Connection pcon, String id) throws DAOException { Connection con = pcon.getConnection(); PreparedStatement ps = null; try { ps = con.prepareStatement("DELETE FROM " + tableName + " WHERE id = ?"); ps.setObject(1, id, Types.OTHER); ps.execute(); } catch (SQLException e) { throw new DAOException(e); } finally { close(ps); } } public void remove(Postgres9Connection pcon, UUID id) throws DAOException { remove(pcon, id.toString()); } /** Removes all entities. All data might be lost. You should call this very carefully. */ public void truncate(Postgres9Connection pcon) throws DAOException { removeAll(pcon, tableName); } public DataIterator<Postgres9Entity> getIterator(Postgres9Connection pcon) throws DAOException { final String sql = "SELECT id, version, body, opt, updatedAt FROM " + tableName; Connection con = pcon.getConnection(); boolean shouldClose = true; PreparedStatement ps = null; ResultSet rs = null; try { ps = con.prepareStatement(sql); rs = ps.executeQuery(); shouldClose = false; } catch (SQLException e) { throw new DAOException(e); } finally { if (shouldClose) { close(rs); close(ps); return null; } } DataMapper<ResultSet, Postgres9Entity> mapper = new DataMapper<ResultSet, Postgres9Entity>() { @Override public Postgres9Entity map(ResultSet rs) throws DAOException { try { String id = rs.getString(1); int version = rs.getInt(2); byte[] body = rs.getBytes(3); byte[] opt = rs.getBytes(4); Timestamp updatedAt = rs.getTimestamp(5); return new Postgres9Entity(id, version, body, opt, updatedAt != null ? new DateTime(updatedAt.getTime()) : null); } catch (SQLException e) { throw new DAOException(e); } } @Override public ResultSet unmap(Postgres9Entity t) throws DAOException { throw new UnsupportedOperationException(); } }; Postgres9StatementAndResultSet sars = new Postgres9StatementAndResultSet(ps, rs); return new Postgres9EntityIterator(mapper, this, pcon, sars); } public int count(Postgres9Connection pcon) throws DAOException { Connection con = pcon.getConnection(); PreparedStatement ps = null; ResultSet rs = null; try { ps = con.prepareStatement("SELECT count(*) FROM " + tableName); rs = ps.executeQuery(); if (rs.next()) return rs.getInt(1); else return 0; } catch (SQLException e) { throw new DAOException(e); } finally { close(rs); close(ps); } } }