package dbfit.fixture;
import dbfit.api.DBEnvironment;
import dbfit.api.DbEnvironmentFactory;
import dbfit.util.DbParameterAccessor;
import dbfit.util.FitNesseTestHost;
import fit.Fixture;
import fit.Parse;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Map;
import static dbfit.util.Direction.*;
import static dbfit.util.ValueNormaliser.normaliseValue;
public class Inspect extends fit.Fixture {
private DBEnvironment environment;
private String objectName;
private String mode;
public static String MODE_PROCEDURE = "PROCEDURE";
public static String MODE_TABLE = "TABLE";
public static String MODE_QUERY = "QUERY";
public Inspect() {
this.environment = DbEnvironmentFactory.getDefaultEnvironment();
}
public Inspect(DBEnvironment dbEnvironment, String mode, String objName) {
this.objectName = objName;
this.mode = mode;
this.environment = dbEnvironment;
}
public void doTable(Parse table) {
if (objectName == null) {
objectName = args[0];
}
try {
if (MODE_PROCEDURE.equalsIgnoreCase(mode)) {
inspectProcedure(table);
} else if (MODE_TABLE.equalsIgnoreCase(mode)) {
inspectTable(table);
} else if (MODE_QUERY.equalsIgnoreCase(mode)) {
inspectQuery(table);
} else {
throw new Exception("Unknown inspect mode " + mode);
}
} catch (Exception e) {
exception(table.parts.parts, e);
}
}
private void inspectTable(Parse table) throws SQLException {
Map<String, DbParameterAccessor> allParams =
environment.getAllColumns(objectName);
if (allParams.isEmpty()) {
throw new SQLException(
"Cannot retrieve list of columns for table or view " +
objectName + " - check spelling and access rights");
}
addRowWithParamNames(table, allParams);
}
private void inspectProcedure(Parse table) throws SQLException {
Map<String, DbParameterAccessor> allParams =
environment.getAllProcedureParameters(objectName);
if (allParams.isEmpty()){
throw new SQLException(
"Cannot retrieve list of parameters for procedure " +
objectName + " - check spelling and access rights");
}
addRowWithParamNames(table, allParams);
}
private void inspectQuery(Parse table) throws SQLException {
try (PreparedStatement st =
environment.createStatementWithBoundFixtureSymbols(
FitNesseTestHost.getInstance(), objectName)) {
ResultSet rs = st.executeQuery();
Parse newRow = getHeaderFromRS(rs);
table.parts.more = newRow;
while (rs.next()) {
newRow.more = getDataRow(rs);
newRow = newRow.more;
}
rs.close();
}
}
private Parse getDataRow(ResultSet rs) throws SQLException {
Parse newRow = new Parse("tr", null, null, null);
ResultSetMetaData rsmd = rs.getMetaData();
Parse prevCell = null;
for (int i = 0; i < rsmd.getColumnCount(); i++) {
Object value = rs.getObject(i + 1);
value = normaliseValue(value);
Parse cell = new Parse("td",
Fixture.gray(value == null ? "null" : value.toString()), null, null);
if (prevCell == null) {
newRow.parts = cell;
} else {
prevCell.more = cell;
}
prevCell = cell;
}
return newRow;
}
private Parse getHeaderFromRS(ResultSet rs) throws SQLException {
Parse newRow = new Parse("tr", null, null, null);
ResultSetMetaData rsmd = rs.getMetaData();
Parse prevCell = null;
for (int i = 0; i < rsmd.getColumnCount(); i++) {
Parse cell = new Parse("td", Fixture.gray(rsmd.getColumnLabel(i + 1)), null, null);
if (prevCell == null) {
newRow.parts = cell;
} else {
prevCell.more = cell;
}
prevCell = cell;
}
return newRow;
}
private void addRowWithParamNames(Parse table, Map<String, DbParameterAccessor> params) {
Parse newRow = new Parse("tr", null, null, null);
table.parts.more = newRow;
Parse prevCell = null;
String orderedNames[] = new String[params.size()];
for (String s : params.keySet()) {
if (params.get(s).getPosition() == -1) {
orderedNames[0] = s;
} else {
orderedNames[params.get(s).getPosition()] = s;
}
}
for (int i = 0; i < orderedNames.length; i++) {
String name = orderedNames[i];
if (name == null) {
name = "";
}
if (params.get(name).doesNotHaveDirection(INPUT)) {
name = name + "?";
}
Parse cell = new Parse("td", Fixture.gray(name), null, null);
if (prevCell == null) {
newRow.parts = cell;
} else {
prevCell.more = cell;
}
prevCell = cell;
}
}
}