// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.pgsimple.v0_6.impl;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Arrays;
import org.openstreetmap.osmosis.core.OsmosisRuntimeException;
import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
import org.openstreetmap.osmosis.core.domain.v0_6.OsmUser;
/**
* Provides functionality common to all database entity builder implementations.
*
* @author Brett Henderson
* @param <T>
* The entity type to be supported.
*/
public abstract class EntityMapper<T extends Entity> {
/**
* Returns the name of the entity to substitute into SQL statements. This is
* a low-tech way of making the queries type independent.
*
* @return The entity name as defined in the database schema.
*/
public abstract String getEntityName();
/**
* Returns the action data type of the entity.
*
* @return The action type.
*/
public abstract ActionDataType getEntityType();
/**
* Returns the class type for the entity.
*
* @return The entity type class.
*/
public abstract Class<T> getEntityClass();
/**
* The SQL SELECT statement for counting entities. It will return a count of
* matching records.
*
* @param filterByEntityId
* If true, a WHERE clause will be added filtering by the entity
* id column.
* @return The SQL string.
*/
public String getSqlSelectCount(boolean filterByEntityId) {
StringBuilder resultSql;
resultSql = new StringBuilder();
resultSql.append("SELECT Count(e.*) AS count FROM " + getEntityName() + "s e");
if (filterByEntityId) {
resultSql.append(" WHERE e.id = ?");
}
return resultSql.toString();
}
/**
* Produces an array of additional column names specific to this entity type
* to be returned by entity queries.
*
* @return The column names.
*/
protected abstract String[] getTypeSpecificFieldNames();
/**
* The SQL SELECT statement for retrieving entity details.
*
* @param filterByEntityId
* If true, a WHERE clause will be added filtering by the entity
* id column.
* @param orderByEntityId
* If true, an ORDER BY clause will be added ordering by the
* entity id column.
* @return The SQL string.
*/
public String getSqlSelect(boolean filterByEntityId, boolean orderByEntityId) {
StringBuilder resultSql;
resultSql = new StringBuilder();
resultSql.append("SELECT e.id, e.version, e.user_id, u.name AS user_name, e.tstamp, e.changeset_id");
for (String fieldName : Arrays.asList(getTypeSpecificFieldNames())) {
resultSql.append(", ").append(fieldName);
}
resultSql.append(" FROM ");
resultSql.append(getEntityName());
resultSql.append("s e");
resultSql.append(" LEFT OUTER JOIN users u ON e.user_id = u.id");
if (filterByEntityId) {
resultSql.append(" WHERE e.id = ?");
}
if (orderByEntityId) {
resultSql.append(" ORDER BY e.id");
}
return resultSql.toString();
}
/**
* The SQL INSERT statement for adding entities.
*
* @param rowCount
* The number of rows to insert in a single statement.
* @return The SQL string.
*/
public String getSqlInsert(int rowCount) {
String[] typeSpecificFieldNames;
StringBuilder resultSql;
typeSpecificFieldNames = getTypeSpecificFieldNames();
resultSql = new StringBuilder();
resultSql.append("INSERT INTO ").append(getEntityName()).append("s");
resultSql.append("(id, version, user_id, tstamp, changeset_id");
for (String fieldName : Arrays.asList(typeSpecificFieldNames)) {
resultSql.append(", ").append(fieldName);
}
resultSql.append(") VALUES ");
for (int row = 0; row < rowCount; row++) {
if (row > 0) {
resultSql.append(", ");
}
resultSql.append("(?, ?, ?, ?, ?");
for (int i = 0; i < typeSpecificFieldNames.length; i++) {
resultSql.append(", ?");
}
resultSql.append(")");
}
return resultSql.toString();
}
/**
* The SQL UPDATE statement for updating entity details.
*
* @param filterByEntityId
* If true, a WHERE clause will be added filtering by the entity
* id column.
* @return The SQL String.
*/
public String getSqlUpdate(boolean filterByEntityId) {
StringBuilder resultSql;
resultSql = new StringBuilder();
resultSql.append("UPDATE ").append(getEntityName())
.append("s SET id = ?, version = ?, user_id = ?, tstamp = ?, changeset_id = ?");
for (String fieldName : Arrays.asList(getTypeSpecificFieldNames())) {
resultSql.append(", ").append(fieldName).append(" = ?");
}
if (filterByEntityId) {
resultSql.append(" WHERE id = ?");
}
return resultSql.toString();
}
/**
* The SQL UPDATE statement for logically deleting entities.
*
* @param filterByEntityId
* If true, a WHERE clause will be added filtering by the entity
* id column.
* @return The SQL String.
*/
public String getSqlDelete(boolean filterByEntityId) {
StringBuilder resultSql;
resultSql = new StringBuilder();
resultSql.append("DELETE FROM ").append(getEntityName()).append("s");
if (filterByEntityId) {
resultSql.append(" WHERE id = ?");
}
return resultSql.toString();
}
/**
* Creates a new entity based upon the current row in the result set.
*
* @param resultSet
* The result set to read from.
* @return The newly built entity object.
*/
public abstract T parseRecord(ResultSet resultSet);
/**
* Creates a new user record based upon the current result set row.
*
* @param resultSet
* The result set to read from.
* @return The newly build user object.
*/
protected OsmUser buildUser(ResultSet resultSet) {
try {
int userId;
OsmUser user;
userId = resultSet.getInt("user_id");
if (userId == OsmUser.NONE.getId()) {
user = OsmUser.NONE;
} else {
user = new OsmUser(
userId,
resultSet.getString("user_name")
);
}
return user;
} catch (SQLException e) {
throw new OsmosisRuntimeException("Unable to build a user from the current recordset row.", e);
}
}
/**
* Sets common entity values as bind variable parameters to an entity insert
* query.
*
* @param statement
* The prepared statement to add the values to.
* @param initialIndex
* The offset index of the first variable to set.
* @param entity
* The entity containing the data to be inserted.
* @return The current parameter offset.
*/
protected int populateCommonEntityParameters(PreparedStatement statement, int initialIndex, Entity entity) {
int prmIndex;
prmIndex = initialIndex;
// We can't write an entity with a null timestamp.
if (entity.getTimestamp() == null) {
throw new OsmosisRuntimeException(
"Entity(" + entity.getType() + ") " + entity.getId() + " does not have a timestamp set.");
}
try {
statement.setLong(prmIndex++, entity.getId());
statement.setInt(prmIndex++, entity.getVersion());
statement.setInt(prmIndex++, entity.getUser().getId());
statement.setTimestamp(prmIndex++, new Timestamp(entity.getTimestamp().getTime()));
statement.setLong(prmIndex++, entity.getChangesetId());
} catch (SQLException e) {
throw new OsmosisRuntimeException(
"Unable to set a prepared statement parameter for entity("
+ entity.getType() + ") " + entity.getId() + ".", e);
}
return prmIndex;
}
/**
* Sets entity values as bind variable parameters to an entity insert query.
*
* @param statement
* The prepared statement to add the values to.
* @param initialIndex
* The offset index of the first variable to set.
* @param entity
* The entity containing the data to be inserted.
* @return The current parameter offset.
*/
public abstract int populateEntityParameters(PreparedStatement statement, int initialIndex, T entity);
}