/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2012-2016 the original author or authors.
*/
package org.assertj.db.type;
import org.assertj.db.type.lettercase.LetterCase;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A request in the database to get values.
* <p>
* The different informations of the request are connection or data source, the SQL request and optionally the parameters
* of the SQL request.
* </p>
* <p>
* Examples of instantiation :
* </p>
* <ul>
* <li>
* <p>
* This {@link Request} point to a request without parameter in a H2 database in memory like indicated in the
* {@link Source}.
* </p>
*
* <pre><code class='java'>
* Source source = new Source("jdbc:h2:mem:test", "sa", "");
* Request request = new Request(source, "select title from movie;");
* </code></pre>
*
* </li>
* <li>
* <p>
* Below the {@link Request} point to a request with {@code 2000} in parameter.<br>
* The {@link Request} use a {@code DataSource} instead of a {@link Source} like above.
* </p>
*
* <pre><code class='java'>
* DataSource dataSource = ...;
* Request request = new Request(dataSource, "select title from movie where year > ?;", 2000);
* </code></pre>
*
* </li>
* </ul>
*
* @author RĂ©gis Pouiller
*
*/
public class Request extends AbstractDbData<Request> {
/**
* SQL request to get the values.
*/
private String request;
/**
* Parameters of the SQL request.
*/
private Object[] parameters;
/**
* Default constructor.
*/
public Request() {
super(Request.class, DataType.REQUEST);
}
/**
* Constructor with a connection.
*
* @param source Source to connect to the database.
* @param request SQL Request to get the values.
* @param parameters Parameters of the SQL request.
*/
public Request(Source source, String request, Object... parameters) {
super(Request.class, DataType.REQUEST, source);
setRequest(request);
this.parameters = parameters;
}
/**
* Constructor with a data source.
*
* @param dataSource Data source.
* @param request SQL Request to get the values.
* @param parameters Parameters of the SQL request.
*/
public Request(DataSource dataSource, String request, Object... parameters) {
super(Request.class, DataType.REQUEST, dataSource);
setRequest(request);
this.parameters = parameters;
}
/**
* Returns the SQL request.
*
* @return The SQL request.
*/
public String getRequest() {
return request;
}
/**
* Sets the SQL request.
*
* @param request The SQL request.
* @return The SQL request.
* @throws NullPointerException If the {@link #request} field is {@code null}.
*/
public Request setRequest(String request) {
if (request == null) {
throw new NullPointerException("request can not be null");
}
this.request = request;
return this;
}
/**
* The parameters of the SQL request.
*
* @return The SQL request.
*/
public Object[] getParameters() {
if (parameters == null) {
return null;
}
return parameters.clone();
}
/**
* Sets the parameters of the SQL request.
*
* @param parameters The parameters of the SQL request.
* @return The parameters of the SQL request.
*/
public Request setParameters(Object... parameters) {
this.parameters = parameters;
return this;
}
/**
* Sets the primary keys name.
*
* @param pksName The primary keys name.
* @return {@code this} instance.
*/
public Request setPksName(String... pksName) {
List<String> pksNameList = new ArrayList<>();
pksNameList.addAll(Arrays.asList(pksName));
super.setPksNameList(pksNameList);
return this;
}
/**
* Collects the columns name from the {@code ResultSet} from the SQL request.
* <p>
* This method use the {@link ResultSetMetaData} from the <code>resultSet</code> parameter to list the name of the
* columns.
* </p>
*
* @param resultSet The {@code ResultSet}.
* @throws SQLException A SQL Exception
*/
private void collectColumnsNameFromResultSet(ResultSet resultSet) throws SQLException {
LetterCase letterCase = getColumnLetterCase();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
List<String> columnsNameList = new ArrayList<>();
for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
String columnName = resultSetMetaData.getColumnLabel(i);
columnsNameList.add(letterCase.convert(columnName));
}
setColumnsNameList(columnsNameList);
controlIfAllThePksNameExistInTheColumns();
}
/**
* Specific implementation of the loading for a {@code Request}.
*
* @see AbstractDbData#loadImpl(Connection)
* @param connection {@link Connection} to the database provided by {@link AbstractDbData#load()} private method.
* @throws NullPointerException If the {@link #request} field is {@code null}.
* @throws SQLException SQL Exception.
*/
@Override
protected void loadImpl(Connection connection) throws SQLException {
if (request == null) {
throw new NullPointerException("request can not be null");
}
try (PreparedStatement statement = connection.prepareStatement(request)) {
for (int i = 0; i < parameters.length; i++) {
statement.setObject(i + 1, parameters[i]);
}
try (ResultSet resultSet = statement.executeQuery()) {
collectColumnsNameFromResultSet(resultSet);
collectRowsFromResultSet(resultSet);
}
}
}
}