DBQueryRow.java
/*
* Copyright 2013 Gregory Graham.
*
* 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.
*/
package nz.co.gregs.dbvolution;
import nz.co.gregs.dbvolution.datatypes.QueryableDatatype;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.*;
import nz.co.gregs.dbvolution.internal.query.QueryDetails;
import nz.co.gregs.separatedstring.SeparatedString;
import nz.co.gregs.separatedstring.SeparatedStringBuilder;
/**
* Contains all the instances of DBRow that are associated with one line of a
* DBQuery request.
*
* <p>
* DBQueryRow represents an individual line within the results of a query.
* However the results within the line are contained in instances of all the
* DBRow subclasses included in the DBQuery.
*
* <p>
* Each instance is accessible thru the
* {@link #get(nz.co.gregs.dbvolution.DBRow) get(DBRow) method}.
*
* @author Gregory Graham
*
*/
public class DBQueryRow extends HashMap<Class<? extends DBRow>, DBRow> {
private static final long serialVersionUID = 1;
private final LinkedHashMap<Object, QueryableDatatype<?>> expressionColumnValues = new LinkedHashMap<>();
private transient final QueryDetails baseQuery;
public DBQueryRow(QueryDetails queryThatThisRowWasGeneratedFor) {
super();
baseQuery = queryThatThisRowWasGeneratedFor;
}
/**
* Returns the instance of exemplar contained within this DBQueryRow.
*
* <p>
* Finds the instance of the class supplied that is relevant to the DBRow and
* returns it.
*
* <p>
* If the exemplar represents an optional table an there were no appropriate
* rows found for that table then NULL will be returned.
*
* <p>
* Criteria set on the exemplar are ignored.
*
* <p>
* For example: Marque thisMarque = myQueryRow.get(new Marque());
*
* @param <E> DBRow type
* @param exemplar exemplar
*
* @return the instance of exemplar that is in the DBQueryRow instance
*/
@SuppressWarnings("unchecked")
public <E extends DBRow> E get(E exemplar) {
return (E) get(exemplar.getClass());
}
/**
* Returns the all DBRow instances contained within this DBQueryRow.
*
* @return all DBRow instances that are in this DBQueryRow instance
*/
public List<DBRow> getAll() {
final ArrayList<DBRow> arrayList = new ArrayList<>();
arrayList.addAll(this.values());
return arrayList;
}
/**
* Print the specified columns to the specified PrintStream as one line.
*
* @param ps ps
* @param columns columns
*/
public void print(PrintStream ps, QueryableDatatype<?>... columns) {
for (QueryableDatatype<?> qdt : columns) {
ps.print("" + qdt + " ");
}
ps.println();
}
/**
* Print the all columns to the specified PrintStream as one line.
*
* @param ps ps
*/
public void print(PrintStream ps) {
values().forEach(row -> ps.print("" + row));
}
public void addExpressionColumnValue(Object key, QueryableDatatype<?> expressionQDT) {
expressionColumnValues.put(key, expressionQDT);
}
public QueryableDatatype<?> getExpressionColumnValue(Object key) {
return expressionColumnValues.get(key);
}
public Map<Object, QueryableDatatype<?>> getExpressionColumns() {
return expressionColumnValues;
}
/**
* Returns all the fields names from all the DBRow types in the DBQueryRow.
*
* <p>
* This is essentially a list of all the columns returned from the database
* query.
*
* <p>
* Column data may not have been populated.
*
* <p>
* Please note this is a crude instrument for accessing the data in this
* DBQueryRow. You should probably be using {@link DBQueryRow#get(nz.co.gregs.dbvolution.DBRow)
* } and using the fields and methods of the individual DBRow classes.
*
* @return a list of field names.
*/
public List<String> getFieldNames() {
List<String> returnList = new ArrayList<String>();
for (DBRow tab : baseQuery.getAllQueryTables()) {
Collection<? extends String> fieldNames = tab.getFieldNames();
for (String fieldName : fieldNames) {
returnList.add(tab.getClass().getSimpleName() + ":" + fieldName);
}
}
return returnList;
}
/**
* Returns all the fields values from all the DBRow types in the DBQueryRow.
*
* <p>
* This is essentially a list of all the values returned from the database
* query.
*
* <p>
* Please note this is a crude instrument for accessing the data in this
* DBQueryRow. You should probably be using {@link DBQueryRow#get(nz.co.gregs.dbvolution.DBRow)
* } and using the fields and methods of the individual DBRow classes.
*
* @param dateFormat format that date should be formatted to.
* @return a list of field names.
*
*/
public List<String> getFieldValues(SimpleDateFormat dateFormat) {
List<String> returnList = new ArrayList<String>();
for (DBRow tab : baseQuery.getAllQueryTables()) {
DBRow actualRow = this.get(tab);
if (actualRow != null) {
returnList.addAll(actualRow.getFieldValues(dateFormat));
} else {
for (String returnList1 : tab.getFieldNames()) {
returnList.add(returnList1);
}
}
}
return returnList;
}
/**
* Convenience method to convert this DBQueryRow into a CSV or TSV type
* header.
*
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @param separatorToUseBetweenValues separatorToUseBetweenValues
* @return a list of all the fields in the DBQueryRow separated by the
* supplied value
*/
public String toSeparatedHeader(String separatorToUseBetweenValues) {
StringBuilder returnStr = new StringBuilder();
String separator = "";
List<String> fieldNames = this.getFieldNames();
for (String fieldName : fieldNames) {
returnStr.append(separator).append("\"").append(fieldName.replaceAll("\"", "\"\"")).append("\"");
separator = separatorToUseBetweenValues;
}
return returnStr.toString();
}
/**
* Convenience method to convert this DBQueryRow into a CSV or TSV type line.
*
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @param separatorToUseBetweenValues separatorToUseBetweenValues
* @return a list of all the values in the DBQueryRow formatted for a TSV or
* CSV file
*/
public String toSeparatedLine(String separatorToUseBetweenValues) {
return toSeparatedLine(separatorToUseBetweenValues, null);
}
/**
* Convenience method to convert this DBQueryRow into a CSV or TSV type line.
*
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @param separatorToUseBetweenValues separatorToUseBetweenValues
* @param dateFormat format that dates should be formatted to.
* @return a list of all the values in the DBQueryRow formatted for a TSV or
* CSV file
*/
public String toSeparatedLine(String separatorToUseBetweenValues, SimpleDateFormat dateFormat) {
StringBuilder returnStr = new StringBuilder();
String separator = "";
List<String> fieldValues = this.getFieldValues(dateFormat);
for (String fieldValue : fieldValues) {
returnStr.append(separator).append("\"").append(fieldValue.replaceAll("\"", "\"\"")).append("\"");
separator = separatorToUseBetweenValues;
}
return returnStr.toString();
}
/**
* Convenience method to convert this DBQueryRow into a CSV file's header.
*
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @return a list of all the fields in the DBQueryRow formatted for a CSV file
*/
public String toCSVHeader() {
return toSeparatedHeader(",");
}
/**
* Convenience method to convert this DBQueryRow into a CSV line.
*
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @return a list of all the values in the DBQueryRow formatted for a CSV file
*/
public String toCSVLine() {
return toSeparatedLine(",");
}
/**
* Convenience method to convert this DBQueryRow into a CSV line.
*
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @param dateFormat dateFormat
* @return a list of all the values in the DBQueryRow formatted for a CSV file
*/
public String toCSVLine(SimpleDateFormat dateFormat) {
return toSeparatedLine(",", dateFormat);
}
/**
* Convenience method to convert this DBQueryRow into a Tab Separated Values
* file's header.
*
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @return a list of all the fields in the DBQueryRow formatted for a TSV file
*/
public String toTabbedHeader() {
return toSeparatedHeader("\t");
}
/**
* Convenience method to convert this DBQueryRow into a Tab Separated Values
* line.
* <p>
* The line separator is not included in the results, to allow for portability
* and post-processing.
*
* @return a list of all the values in the DBQueryRow formatted for a TSV file
* @throws java.lang.IllegalAccessException java.lang.IllegalAccessException
*
*/
public String toTabbedLine() throws IllegalArgumentException, IllegalAccessException {
return toSeparatedLine("\t");
}
@Override
public DBQueryRow clone() {
return (DBQueryRow) super.clone();
}
@Override
public String toString() {
SeparatedString sepString = SeparatedStringBuilder
.forSeparator(", ")
.withKeyValueSeparator("=")
.withPrefix("{")
.withSuffix("}")
.useWhenEmpty("{}");
var entrySet = entrySet();
ArrayList<Entry<Class<? extends DBRow>, DBRow>> entryList = new ArrayList<>(entrySet);
entryList.sort((original, other) -> {
return original.getKey().getCanonicalName().compareTo(other.getKey().getCanonicalName());
});
for (Entry<Class<? extends DBRow>, DBRow> entry : entryList) {
sepString.add(entry.getKey().toString(),entry.getValue().toString());
}
var entrySet2 = expressionColumnValues.entrySet();
ArrayList<Entry<Object, QueryableDatatype<?>>> entryList2 = new ArrayList<>(entrySet2);
entryList2.sort((original, other) -> {
return original.getKey().toString().compareTo(other.getKey().toString());
});
for (Entry<Object, QueryableDatatype<?>> entry2 : entryList2) {
sepString.add(entry2.getKey().toString(),entry2.getValue().toString());
}
final String toString = sepString.toString();
return toString;
}
}