package com.supaham.commons.jdbc.sql;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.supaham.commons.utils.StringUtils.checkNotNullOrEmpty;
import com.supaham.commons.jdbc.utils.SQLUtils;
import com.supaham.commons.placeholders.PlaceholderData;
import com.supaham.commons.placeholders.PlaceholderSet;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.Map;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents a SQL database manager used for interacting with a SQL database.
*/
public class SQLDatabase {
private final Logger logger;
private final SpringJDBCAgent jdbcAgent;
private final TableMap tableMap = new TableMap();
public SQLDatabase(@Nonnull Logger logger, @Nonnull SpringJDBCAgent jdbcAgent) {
checkNotNull(logger, "logger cannot be null.");
checkNotNull(jdbcAgent, "jdbc agent cannot be null.");
this.logger = logger;
this.jdbcAgent = jdbcAgent;
}
/**
* Checks whether tables exist.
*/
public void checkTables() {
checkTables(null);
}
/**
* Checks whether tables exist.
*/
public void checkTables(@Nullable PlaceholderSet placeholderSet) {
JdbcTemplate jdbcTemplate = this.jdbcAgent.createJdbcTemplate();
for (Table table : this.tableMap.values()) {
checkTable(jdbcTemplate, table, placeholderSet);
}
}
/**
* Checks whether a table (by id) exists in this {@link SQLDatabase}. If it does not exist it is
* created using its {@link Table} schema. This method is equivalent to calling {@code
* checkTable(Table)}, where the {@link Table} instance is retrieved via {@link
* #getTable(String)}.
*
* @param tableId table id to check out
*
* @return true if the table did not exist and was created, otherwise null if {@code tableId} is
* not a valid tableId in this {@link SQLDatabase}
*
* @see #checkTable(JdbcTemplate, Table)
*/
@Nullable
public Boolean checkTable(@Nonnull String tableId) {
checkNotNullOrEmpty(tableId, "tableId");
Table table = getTable(tableId);
return table != null ? checkTable(table) : null;
}
/**
* Checks whether a {@link Table} exists in this {@link SQLDatabase}. If it does not exist it is
* created using its own schema. This method is equivalent to calling {@code
* checkTable(SpringJDBCAgent.createJdbcTemplate(), Table)}.
*
* @param table table to check out
*
* @return true if the table did not exist and was created
*
* @see #checkTable(JdbcTemplate, Table)
*/
public boolean checkTable(@Nonnull Table table) {
return checkTable(this.jdbcAgent.createJdbcTemplate(), table);
}
/**
* Checks whether a table (by id) exists in this {@link SQLDatabase}. If it does not exist it is
* created using its {@link Table} schema. This method is equivalent to calling {@code
* checkTable(JdbcTemplate, Table)}, where the {@link Table} instance is retrieved via {@link
* #getTable(String)}.
*
* @param tableId table id to check out
*
* @return true if the table did not exist and was created, otherwise null if {@code tableId} is
* not a valid tableId in this {@link SQLDatabase}
*
* @see #checkTable(JdbcTemplate, Table)
*/
@Nullable
public Boolean checkTable(@Nonnull JdbcTemplate template, @Nonnull String tableId) {
checkNotNullOrEmpty(tableId, "tableId");
Table table = getTable(tableId);
return table != null ? checkTable(template, table) : null;
}
/**
* Checks whether a {@link Table} exists in this {@link SQLDatabase}. If it does not exist it is
* created using its own schema. This method is equivalent to calling {@code
* checkTable(JdbcTemplate, Table, null)}.
*
* @param template template to use for checking the table, in case it needs to be created
* @param table table to check out
*
* @return true if the table did not exist and was created
*
* @see #checkTable(JdbcTemplate, Table, PlaceholderSet)
*/
public boolean checkTable(@Nonnull JdbcTemplate template, @Nonnull Table table) {
return checkTable(template, table, null);
}
/**
* Checks whether a table (by id) exists in this {@link SQLDatabase}. If it does not exist it is
* created using its {@link Table} schema. This method is equivalent to calling {@link
* #checkTable(Table, PlaceholderSet)}, where the {@link Table} instance is retrieved via {@link
* #getTable(String)}.
*
* @param tableId table id to check out
*
* @return true if the table did not exist and was created, otherwise null if {@code tableId} is
* not a valid tableId in this {@link SQLDatabase}
*
* @see #checkTable(JdbcTemplate, Table)
*/
@Nullable
public Boolean checkTable(@Nonnull String tableId,
@Nullable PlaceholderSet placeholders) {
checkNotNullOrEmpty(tableId, "tableId");
Table table = getTable(tableId);
return table != null ? checkTable(table, placeholders) : null;
}
/**
* Checks whether a {@link Table} exists in this {@link SQLDatabase}. If it does not exist it is
* created using its own schema. This method is equivalent to calling {@code
* checkTable(SpringJDBCAgent.createJdbcTemplate(), Table, PlaceholderSet)}
*
* @param table table to check out
* @param placeholders {@link PlaceholderSet} to use on the schema
*
* @return true if the table did not exist and was created
*
* @see #checkTable(JdbcTemplate, Table, PlaceholderSet)
*/
public boolean checkTable(@Nonnull Table table,
@Nullable PlaceholderSet placeholders) {
return checkTable(this.jdbcAgent.createJdbcTemplate(), table, placeholders);
}
/**
* Checks whether a {@link Table} exists in this {@link SQLDatabase}. If it does not exist it is
* created using its own schema.
*
* @param template template to use for checking the table, in case it needs to be created
* @param table table to check out
* @param placeholders {@link PlaceholderSet} to use on the schema
*
* @return true if the table did not exist and was created
*/
public boolean checkTable(@Nonnull JdbcTemplate template, @Nonnull Table table,
@Nullable PlaceholderSet placeholders) {
checkNotNull(template, "template cannot be null.");
checkNotNull(table, "table cannot be null.");
checkArgument(this.tableMap.hasTable(table), "table doesn't belong to this database.");
// Don't attempt to create the table if it's schema is NO_SCHEMA
if (table.getSchema().equals(Table.NO_SCHEMA)) {
return true;
}
String name = table.getName();
this.logger.fine("Checking table '" + name + "'.");
if (!SQLUtils.hasTable(this.jdbcAgent.getDataSource(), name)) {
this.logger.fine("'" + name + "' table doesn't exist, creating it...");
String schema = table.getSchema();
if (placeholders != null && !placeholders.isEmpty()) {
PlaceholderData data = PlaceholderData.builder()
.input(schema)
.put(table)
.put(template).build();
schema = placeholders.apply(data);
}
template.execute(schema);
return true;
} else {
this.logger.finer("table '" + name + "' already exists");
return false;
}
}
public SpringJDBCAgent getJdbcAgent() {
return jdbcAgent;
}
/**
* Gets this {@link SQLDatabase}'s {@link TableMap}.
*
* @return {@link TableMap} instance
*/
public TableMap getTableMap() {
return this.tableMap;
}
/* ================================
* >> DELEGATE METHODS
* ================================ */
/**
* @see TableMap#hasTable(String)
*/
public boolean hasTable(@Nonnull String tableId) {
return tableMap.hasTable(tableId);
}
/**
* @see TableMap#hasTable(Table)
*/
public boolean hasTable(@Nonnull Table table) {
return tableMap.hasTable(table);
}
/**
* @see TableMap#hasTableByName(String)
*/
public boolean hasTableByName(@Nonnull String tableName) {
return tableMap.hasTableByName(tableName);
}
/**
* @see TableMap#getTableIdByName(String)
*/
@Nullable
public String getTableIdByName(@Nullable String tableName) {
return tableMap.getTableIdByName(tableName);
}
/**
* @see TableMap#getTable(String)
*/
@Nullable
public Table getTable(@Nullable String tableId) {
return tableMap.getTable(tableId);
}
/**
* @see TableMap#getTableName(String)
*/
@Nullable
public String getTableName(@Nullable String tableId) {
return tableMap.getTableName(tableId);
}
/**
* Creates and adds a new {@link Table} with the schema as {@link Table#NO_SCHEMA} which
* specifies
* that when checking the table, don't bother creating if it doesn't exist. This is equivalent to
* calling {@code TableMap.addTable(String, String, null)}.
*
* @see TableMap#addTable(String, String, String)
*/
public void addTable(@Nonnull String id, @Nonnull String name)
throws IllegalArgumentException {
tableMap.addTable(id, name, null);
}
/**
* @see TableMap#addTable(String, String, String)
*/
public void addTable(@Nonnull String id, @Nonnull String name, @Nullable String schema)
throws IllegalArgumentException {
tableMap.addTable(id, name, schema);
}
/**
* @see TableMap#addTable(String, Table)
*/
public void addTable(@Nonnull String id, @Nonnull Table table) throws IllegalArgumentException {
tableMap.addTable(id, table);
}
/**
* @see TableMap#removeTable(Table)
*/
public boolean removeTable(@Nonnull Table table) {
return tableMap.removeTable(table);
}
/**
* @see TableMap#removeTable(String)
*/
@Nullable
public Table removeTable(@Nonnull String id) {
return tableMap.removeTable(id);
}
/**
* @see TableMap#getTables()
*/
public Map<String, Table> getTables() {
return this.tableMap.getTables();
}
}