All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jooq.impl.ResultImpl Maven / Gradle / Ivy

There is a newer version: 0.10.0
Show newest version
/**
 * Copyright (c) 2009-2014, Data Geekery GmbH (http://www.datageekery.com)
 * All rights reserved.
 *
 * This work is dual-licensed
 * - under the Apache Software License 2.0 (the "ASL")
 * - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
 * =============================================================================
 * You may choose which license applies to you:
 *
 * - If you're using this work with Open Source databases, you may choose
 *   either ASL or jOOQ License.
 * - If you're using this work with at least one commercial database, you must
 *   choose jOOQ License
 *
 * For more information, please visit http://www.jooq.org/licenses
 *
 * Apache Software License 2.0:
 * -----------------------------------------------------------------------------
 * 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.
 *
 * jOOQ License and Maintenance Agreement:
 * -----------------------------------------------------------------------------
 * Data Geekery grants the Customer the non-exclusive, timely limited and
 * non-transferable license to install and use the Software under the terms of
 * the jOOQ License and Maintenance Agreement.
 *
 * This library is distributed with a LIMITED WARRANTY. See the jOOQ License
 * and Maintenance Agreement for more details: http://www.jooq.org/licensing
 */

package org.jooq.impl;

import static java.lang.Math.max;
import static java.lang.Math.min;
import static org.jooq.impl.DSL.insertInto;
import static org.jooq.impl.DSL.tableByName;
import static org.jooq.impl.Utils.indexOrFail;
import static org.jooq.tools.StringUtils.abbreviate;
import static org.jooq.tools.StringUtils.leftPad;
import static org.jooq.tools.StringUtils.rightPad;

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.jooq.AttachableInternal;
import org.jooq.Configuration;
import org.jooq.Converter;
import org.jooq.DSLContext;
import org.jooq.EnumType;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Record10;
import org.jooq.Record11;
import org.jooq.Record12;
import org.jooq.Record13;
import org.jooq.Record14;
import org.jooq.Record15;
import org.jooq.Record16;
import org.jooq.Record17;
import org.jooq.Record18;
import org.jooq.Record19;
import org.jooq.Record2;
import org.jooq.Record20;
import org.jooq.Record21;
import org.jooq.Record22;
import org.jooq.Record3;
import org.jooq.Record4;
import org.jooq.Record5;
import org.jooq.Record6;
import org.jooq.Record7;
import org.jooq.Record8;
import org.jooq.Record9;
import org.jooq.RecordHandler;
import org.jooq.RecordMapper;
import org.jooq.RecordType;
import org.jooq.Result;
import org.jooq.Row;
import org.jooq.Table;
import org.jooq.TableRecord;
import org.jooq.exception.IOException;
import org.jooq.exception.InvalidResultException;
import org.jooq.tools.Convert;
import org.jooq.tools.StringUtils;
import org.jooq.tools.jdbc.MockResultSet;
import org.jooq.tools.json.JSONObject;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
 * @author Lukas Eder
 * @author Ivan Dugic
 */
@SuppressWarnings({"rawtypes", "unchecked" })
class ResultImpl implements Result, AttachableInternal {

    /**
     * Generated UID
     */
    private static final long serialVersionUID = 6416154375799578362L;

    private Configuration     configuration;
    private final Fields   fields;
    private final List     records;

    ResultImpl(Configuration configuration, Collection> fields) {
        this(configuration, new Fields(fields));
    }

    ResultImpl(Configuration configuration, Field... fields) {
        this(configuration, new Fields(fields));
    }

    ResultImpl(Configuration configuration, Fields fields) {
        this.configuration = configuration;
        this.fields = fields;
        this.records = new ArrayList();
    }

    // -------------------------------------------------------------------------
    // XXX: Attachable API
    // -------------------------------------------------------------------------

    @Override
    public final void attach(Configuration c) {
        this.configuration = c;

        for (R record : records) {
            if (record != null) {
                record.attach(c);
            }
        }
    }

    @Override
    public final void detach() {
        attach(null);
    }

    @Override
    public final Configuration configuration() {
        return configuration;
    }

    // -------------------------------------------------------------------------
    // XXX: Result API
    // -------------------------------------------------------------------------

    @Override
    public final RecordType recordType() {
        return fields;
    }

    @Override
    public final Row fieldsRow() {
        return new RowImpl(fields);
    }

    @Override
    public final  Field field(Field field) {
        return fields.field(field);
    }

    @Override
    public final Field field(String name) {
        return fields.field(name);
    }

    @Override
    public final Field field(int index) {
        return fields.field(index);
    }

    @Override
    public final Field[] fields() {
        return fields.fields().clone();
    }

    @Override
    public final boolean isEmpty() {
        return records.isEmpty();
    }

    @Override
    public final boolean isNotEmpty() {
        return !records.isEmpty();
    }

    @Override
    public final  T getValue(int index, Field field) {
        return get(index).getValue(field);
    }

    @Override
    @Deprecated
    public final  T getValue(int index, Field field, T defaultValue) {
        return get(index).getValue(field, defaultValue);
    }

    @Override
    public final Object getValue(int index, int fieldIndex) {
        return get(index).getValue(fieldIndex);
    }

    @Override
    @Deprecated
    public final Object getValue(int index, int fieldIndex, Object defaultValue) {
        return get(index).getValue(fieldIndex, defaultValue);
    }

    @Override
    public final Object getValue(int index, String fieldName) {
        return get(index).getValue(fieldName);
    }

    @Override
    @Deprecated
    public final Object getValue(int index, String fieldName, Object defaultValue) {
        return get(index).getValue(fieldName, defaultValue);
    }

    @Override
    public final  List getValues(Field field) {
        return (List) getValues(indexOrFail(fieldsRow(), field));
    }

    @Override
    public final  List getValues(Field field, Class type) {
        return Convert.convert(getValues(field), type);
    }

    @Override
    public final  List getValues(Field field, Converter converter) {
        return Convert.convert(getValues(field), converter);
    }

    @Override
    public final List getValues(int fieldIndex) {
        List result = new ArrayList(size());

        for (R record : this) {
            result.add(record.getValue(fieldIndex));
        }

        return result;
    }

    @Override
    public final  List getValues(int fieldIndex, Class type) {
        return Convert.convert(getValues(fieldIndex), type);
    }

    @Override
    public final  List getValues(int fieldIndex, Converter converter) {
        return Convert.convert(getValues(fieldIndex), converter);
    }

    @Override
    public final List getValues(String fieldName) {
        return getValues(field(fieldName));
    }

    @Override
    public final  List getValues(String fieldName, Class type) {
        return Convert.convert(getValues(fieldName), type);
    }

    @Override
    public final  List getValues(String fieldName, Converter converter) {
        return Convert.convert(getValues(fieldName), converter);
    }

    final void addRecord(R record) {
        records.add(record);
    }

    @Override
    public final String format() {
        StringWriter writer = new StringWriter();
        format(writer);
        return writer.toString();
    }

    @Override
    public final void format(OutputStream stream) {
        format(new OutputStreamWriter(stream));
    }

    @Override
    public final void format(Writer writer) {
        format(writer, 50);
    }

    @Override
    public final String format(int maxRecords) {
        StringWriter writer = new StringWriter();
        format(writer, maxRecords);
        return writer.toString();
    }

    @Override
    public final void format(OutputStream stream, int maxRecords) {
        format(new OutputStreamWriter(stream), maxRecords);
    }

    @Override
    public final void format(Writer writer, int maxRecords) {
        try {
            final int COL_MIN_WIDTH = 4;
            final int COL_MAX_WIDTH = 50;

            // Numeric columns have greater max width because values are aligned
            final int NUM_COL_MAX_WIDTH = 100;

            // The max number of records that will be considered for formatting purposes
            final int MAX_RECORDS = min(50, maxRecords);

            // Get max decimal places for numeric type columns
            final int[] decimalPlaces = new int[fields.fields.length];
            final int[] widths = new int[fields.fields.length];

            for (int index = 0; index < fields.fields.length; index++) {
                if (Number.class.isAssignableFrom(fields.fields[index].getType())) {
                    List decimalPlacesList = new ArrayList();

                    // Initialize
                    decimalPlacesList.add(0);

                    // Collect all decimal places for the column values
                    String value;
                    for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
                        value = format0(getValue(i, index), get(i).changed(index));
                        decimalPlacesList.add(getDecimalPlaces(value));
                    }

                    // Find max
                    decimalPlaces[index] = Collections.max(decimalPlacesList);
                }
            }

            // Get max column widths
            int colMaxWidth;
            for (int index = 0; index < fields.fields.length; index++) {

                // Is number column?
                boolean isNumCol = Number.class.isAssignableFrom(fields.fields[index].getType());

                colMaxWidth = isNumCol ? NUM_COL_MAX_WIDTH : COL_MAX_WIDTH;

                // Collect all widths for the column
                List widthList = new ArrayList();

                // Add column name width first
                widthList.add(min(colMaxWidth, max(COL_MIN_WIDTH, fields.fields[index].getName().length())));

                // Add column values width
                String value;
                for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
                    value = format0(getValue(i, index), get(i).changed(index));
                    // Align number values before width is calculated
                    if (isNumCol) {
                        value = alignNumberValue(decimalPlaces[index], value);
                    }

                    widthList.add(min(colMaxWidth, value.length()));
                }

                // Find max
                widths[index] = Collections.max(widthList);
            }

            // Begin the writing
            // ---------------------------------------------------------------------

            // Write top line
            writer.append("+");
            for (int index = 0; index < fields.fields.length; index++) {
                writer.append(rightPad("", widths[index], "-"));
                writer.append("+");
            }

            // Write headers
            writer.append("\n|");
            for (int index = 0; index < fields.fields.length; index++) {
                String padded;

                if (Number.class.isAssignableFrom(fields.fields[index].getType())) {
                    padded = leftPad(fields.fields[index].getName(), widths[index]);
                }
                else {
                    padded = rightPad(fields.fields[index].getName(), widths[index]);
                }

                writer.append(abbreviate(padded, widths[index]));
                writer.append("|");
            }

            // Write separator
            writer.append("\n+");
            for (int index = 0; index < fields.fields.length; index++) {
                writer.append(rightPad("", widths[index], "-"));
                writer.append("+");
            }

            // Write columns
            for (int i = 0; i < min(maxRecords, size()); i++) {
                writer.append("\n|");

                for (int index = 0; index < fields.fields.length; index++) {
                    String value = format0(getValue(i, index), get(i).changed(index)).replace("\n", "{lf}").replace("\r", "{cr}");

                    String padded;
                    if (Number.class.isAssignableFrom(fields.fields[index].getType())) {
                        // Align number value before left pad
                        value = alignNumberValue(decimalPlaces[index], value);

                        // Left pad
                        padded = leftPad(value, widths[index]);
                    }
                    else {
                        // Right pad
                        padded = rightPad(value, widths[index]);
                    }

                    writer.append(abbreviate(padded, widths[index]));
                    writer.append("|");
                }
            }

            // Write bottom line
            if (size() > 0) {
                writer.append("\n+");

                for (int index = 0; index < fields.fields.length; index++) {
                    writer.append(rightPad("", widths[index], "-"));
                    writer.append("+");
                }
            }

            // Write truncation message, if applicable
            if (maxRecords < size()) {
                writer.append("\n|...");
                writer.append("" + (size() - maxRecords));
                writer.append(" record(s) truncated...");
            }
        }
        catch (java.io.IOException e) {
            throw new IOException("Exception while writing TEXT", e);
        }
    }

    private static final String alignNumberValue(Integer columnDecimalPlaces, String value) {
        if (!"{null}".equals(value) && columnDecimalPlaces != 0) {
            int decimalPlaces = getDecimalPlaces(value);
            int rightPadSize = value.length() + columnDecimalPlaces - decimalPlaces;

            if (decimalPlaces == 0) {
                // If integer value, add one for decimal point
                value = rightPad(value, rightPadSize + 1);
            }
            else {
                value = rightPad(value, rightPadSize);
            }
        }

        return value;
    }

    private static final int getDecimalPlaces(String value) {
        int decimalPlaces = 0;

        int dotIndex = value.indexOf(".");
        if (dotIndex != -1) {
            decimalPlaces = value.length() - dotIndex - 1;
        }

        return decimalPlaces;
    }

    @Override
    public final String formatHTML() {
        StringWriter writer = new StringWriter();
        formatHTML(writer);
        return writer.toString();
    }

    @Override
    public final void formatHTML(OutputStream stream) {
        formatHTML(new OutputStreamWriter(stream));
    }

    @Override
    public final void formatHTML(Writer writer) {
        try {
            writer.append("");
            writer.append("");
            writer.append("");

            for (Field field : fields.fields) {
                writer.append("");
            }

            writer.append("");
            writer.append("");
            writer.append("");

            for (Record record : this) {
                writer.append("");

                for (int index = 0; index < fields.fields.length; index++) {
                    writer.append("");
                }

                writer.append("");
            }

            writer.append("");
            writer.append("
"); writer.append(field.getName()); writer.append("
"); writer.append(format0(record.getValue(index), false)); writer.append("
"); } catch (java.io.IOException e) { throw new IOException("Exception while writing HTML", e); } } @Override public final String formatCSV() { StringWriter writer = new StringWriter(); formatCSV(writer); return writer.toString(); } @Override public final void formatCSV(OutputStream stream) { formatCSV(new OutputStreamWriter(stream)); } @Override public final void formatCSV(Writer writer) { formatCSV(writer, ',', ""); } @Override public final String formatCSV(char delimiter) { StringWriter writer = new StringWriter(); formatCSV(writer, delimiter); return writer.toString(); } @Override public final void formatCSV(OutputStream stream, char delimiter) { formatCSV(new OutputStreamWriter(stream), delimiter); } @Override public final void formatCSV(Writer writer, char delimiter) { formatCSV(delimiter, ""); } @Override public final String formatCSV(char delimiter, String nullString) { StringWriter writer = new StringWriter(); formatCSV(writer, delimiter, nullString); return writer.toString(); } @Override public final void formatCSV(OutputStream stream, char delimiter, String nullString) { formatCSV(new OutputStreamWriter(stream), delimiter, nullString); } @Override public final void formatCSV(Writer writer, char delimiter, String nullString) { try { String sep1 = ""; for (Field field : fields.fields) { writer.append(sep1); writer.append(formatCSV0(field.getName(), "")); sep1 = Character.toString(delimiter); } writer.append("\n"); for (Record record : this) { String sep2 = ""; for (int index = 0; index < fields.fields.length; index++) { writer.append(sep2); writer.append(formatCSV0(record.getValue(index), nullString)); sep2 = Character.toString(delimiter); } writer.append("\n"); } } catch (java.io.IOException e) { throw new IOException("Exception while writing CSV", e); } } private final String formatCSV0(Object value, String nullString) { // Escape null and empty strings if (value == null || "".equals(value)) { if (StringUtils.isEmpty(nullString)) { return "\"\""; } else { return nullString; } } String result = format0(value, false); if (StringUtils.containsAny(result, ',', ';', '\t', '"', '\n', '\r', '\'', '\\')) { return "\"" + result.replace("\\", "\\\\").replace("\"", "\"\"") + "\""; } else { return result; } } private static final String format0(Object value, boolean changed) { String formatted = changed ? "*" : ""; if (value == null) { formatted += "{null}"; } else if (value.getClass() == byte[].class) { formatted += Arrays.toString((byte[]) value); } else if (value.getClass().isArray()) { formatted += Arrays.toString((Object[]) value); } else if (value instanceof EnumType) { formatted += ((EnumType) value).getLiteral(); } else { formatted += value.toString(); } return formatted; } @Override public final String formatJSON() { StringWriter writer = new StringWriter(); formatJSON(writer); return writer.toString(); } @Override public final void formatJSON(OutputStream stream) { formatJSON(new OutputStreamWriter(stream)); } @Override public final void formatJSON(Writer writer) { try { List> f = new ArrayList>(); List> r = new ArrayList>(); Map fieldMap; for (Field field : fields.fields) { fieldMap = new LinkedHashMap(); fieldMap.put("name", field.getName()); fieldMap.put("type", field.getDataType().getTypeName().toUpperCase()); f.add(fieldMap); } for (Record record : this) { List list = new ArrayList(); for (int index = 0; index < fields.fields.length; index++) { list.add(record.getValue(index)); } r.add(list); } Map> map = new LinkedHashMap>(); map.put("fields", f); map.put("records", r); writer.append(JSONObject.toJSONString(map)); } catch (java.io.IOException e) { throw new IOException("Exception while writing JSON", e); } } @Override public final String formatXML() { StringWriter writer = new StringWriter(); formatXML(writer); return writer.toString(); } @Override public final void formatXML(OutputStream stream) { formatXML(new OutputStreamWriter(stream)); } @Override public final void formatXML(Writer writer) { try { writer.append(""); writer.append(""); for (Field field : fields.fields) { writer.append(""); } writer.append(""); writer.append(""); for (Record record : this) { writer.append(""); for (int index = 0; index < fields.fields.length; index++) { Object value = record.getValue(index); writer.append(""); } else { writer.append(">"); writer.append(escapeXML(format0(value, false))); writer.append(""); } } writer.append(""); } writer.append(""); writer.append(""); } catch (java.io.IOException e) { throw new IOException("Exception while writing XML", e); } } @Override public final String formatInsert() { StringWriter writer = new StringWriter(); formatInsert(writer); return writer.toString(); } @Override public final void formatInsert(OutputStream stream) { formatInsert(new OutputStreamWriter(stream)); } @Override public final void formatInsert(Writer writer) { Table table = null; if (records.size() > 0 && records.get(0) instanceof TableRecord) table = ((TableRecord) records.get(0)).getTable(); if (table == null) table = tableByName("UNKNOWN_TABLE"); formatInsert(writer, table, fields()); } @Override public final String formatInsert(Table table, Field... f) { StringWriter writer = new StringWriter(); formatInsert(writer, table, f); return writer.toString(); } @Override public final void formatInsert(OutputStream stream, Table table, Field... f) { formatInsert(new OutputStreamWriter(stream), table, f); } @Override public final void formatInsert(Writer writer, Table table, Field... f) { DSLContext ctx = DSL.using(configuration()); try { for (R record : this) { writer.append(ctx.renderInlined(insertInto(table, f).values(record.intoArray()))); writer.append(";\n"); } } catch (java.io.IOException e) { throw new IOException("Exception while writing INSERTs", e); } } @Override public final Document intoXML() { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.newDocument(); Element eResult = document.createElement("result"); eResult.setAttribute("xmlns", "http://www.jooq.org/xsd/jooq-export-2.6.0.xsd"); document.appendChild(eResult); Element eFields = document.createElement("fields"); eResult.appendChild(eFields); for (Field field : fields.fields) { Element eField = document.createElement("field"); eField.setAttribute("name", field.getName()); eField.setAttribute("type", field.getDataType().getTypeName().toUpperCase()); eFields.appendChild(eField); } Element eRecords = document.createElement("records"); eResult.appendChild(eRecords); for (Record record : this) { Element eRecord = document.createElement("record"); eRecords.appendChild(eRecord); for (int index = 0; index < fields.fields.length; index++) { Field field = fields.fields[index]; Object value = record.getValue(index); Element eValue = document.createElement("value"); eValue.setAttribute("field", field.getName()); eRecord.appendChild(eValue); if (value != null) { eValue.setTextContent(format0(value, false)); } } } return document; } catch (ParserConfigurationException ignore) { throw new RuntimeException(ignore); } } @Override public final H intoXML(H handler) throws SAXException { Attributes empty = new AttributesImpl(); handler.startDocument(); handler.startPrefixMapping("", "http://www.jooq.org/xsd/jooq-export-2.6.0.xsd"); handler.startElement("", "", "result", empty); handler.startElement("", "", "fields", empty); for (Field field : fields.fields) { AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "", "name", "CDATA", field.getName()); attrs.addAttribute("", "", "type", "CDATA", field.getDataType().getTypeName().toUpperCase()); handler.startElement("", "", "field", attrs); handler.endElement("", "", "field"); } handler.endElement("", "", "fields"); handler.startElement("", "", "records", empty); for (Record record : this) { handler.startElement("", "", "record", empty); for (int index = 0; index < fields.fields.length; index++) { Field field = fields.fields[index]; Object value = record.getValue(index); AttributesImpl attrs = new AttributesImpl(); attrs.addAttribute("", "", "field", "CDATA", field.getName()); handler.startElement("", "", "value", attrs); if (value != null) { char[] chars = format0(value, false).toCharArray(); handler.characters(chars, 0, chars.length); } handler.endElement("", "", "value"); } handler.endElement("", "", "record"); } handler.endElement("", "", "records"); handler.endPrefixMapping(""); handler.endDocument(); return handler; } private final String escapeXML(String string) { return StringUtils.replaceEach(string, new String[] { "\"", "'", "<", ">", "&" }, new String[] { """, "'", "<", ">", "&"}); } @Override public final List> intoMaps() { List> list = new ArrayList>(); for (R record : this) { list.add(record.intoMap()); } return list; } @Override public final Map intoMap(Field key) { int index = indexOrFail(fieldsRow(), key); Map map = new LinkedHashMap(); for (R record : this) { if (map.put((K) record.getValue(index), record) != null) { throw new InvalidResultException("Key " + key + " is not unique in Result for " + this); } } return map; } @Override public final Map intoMap(Field key, Field value) { int kIndex = indexOrFail(fieldsRow(), key); int vIndex = indexOrFail(fieldsRow(), value); Map map = new LinkedHashMap(); for (R record : this) { if (map.put((K) record.getValue(kIndex), (V) record.getValue(vIndex)) != null) { throw new InvalidResultException("Key " + key + " is not unique in Result for " + this); } } return map; } @Override public final Map intoMap(Field[] keys) { if (keys == null) { keys = new Field[0]; } Map map = new LinkedHashMap(); for (R record : this) { RecordImpl key = new RecordImpl(keys); for (Field field : keys) { Utils.copyValue(key, field, record, field); } if (map.put(key, record) != null) { throw new InvalidResultException("Key list " + Arrays.asList(keys) + " is not unique in Result for " + this); } } return map; } @Override public final Map, E> intoMap(Field[] keys, Class type) { return intoMap(keys, Utils.configuration(this).recordMapperProvider().provide(fields, type)); } @Override public final Map, E> intoMap(Field[] keys, RecordMapper mapper) { if (keys == null) { keys = new Field[0]; } Map, E> map = new LinkedHashMap, E>(); for (R record : this) { List keyValueList = new ArrayList(); for (Field key : keys) { keyValueList.add(record.getValue(key)); } if (map.put(keyValueList, mapper.map(record)) != null) { throw new InvalidResultException("Key list " + keyValueList + " is not unique in Result for " + this); } } return map; } @Override public final Map intoMap(Table table) { Map map = new LinkedHashMap(); for (R record : this) { S key = record.into(table); if (map.put(key, record) != null) { throw new InvalidResultException("Key list " + key + " is not unique in Result for " + this); } } return map; } @Override public final Map intoMap(Table table, Class type) { return intoMap(table, Utils.configuration(this).recordMapperProvider().provide(fields, type)); } @Override public final Map intoMap(Table table, RecordMapper mapper) { Map map = new LinkedHashMap(); for (R record : this) { S key = record.into(table); if (map.put(key, mapper.map(record)) != null) { throw new InvalidResultException("Key list " + key + " is not unique in Result for " + this); } } return map; } @Override public final Map intoMap(Field key, Class type) { return intoMap(key, Utils.configuration(this).recordMapperProvider().provide(fields, type)); } @Override public final Map intoMap(Field key, RecordMapper mapper) { int index = indexOrFail(fieldsRow(), key); Map map = new LinkedHashMap(); for (R record : this) { if (map.put((K) record.getValue(index), mapper.map(record)) != null) { throw new InvalidResultException("Key " + key + " is not unique in Result for " + this); } } return map; } @Override public final Map> intoGroups(Field key) { int index = indexOrFail(fieldsRow(), key); Map> map = new LinkedHashMap>(); for (R record : this) { K val = (K) record.getValue(index); Result result = map.get(val); if (result == null) { result = new ResultImpl(configuration, fields); map.put(val, result); } result.add(record); } return map; } @Override public final Map> intoGroups(Field key, Field value) { int kIndex = indexOrFail(fieldsRow(), key); int vIndex = indexOrFail(fieldsRow(), value); Map> map = new LinkedHashMap>(); for (R record : this) { K k = (K) record.getValue(kIndex); V v = (V) record.getValue(vIndex); List result = map.get(k); if (result == null) { result = new ArrayList(); map.put(k, result); } result.add(v); } return map; } @Override public final Map> intoGroups(Field key, Class type) { return intoGroups(key, Utils.configuration(this).recordMapperProvider().provide(fields, type)); } @Override public final Map> intoGroups(Field key, RecordMapper mapper) { int index = indexOrFail(fieldsRow(), key); Map> map = new LinkedHashMap>(); for (R record : this) { K keyVal = (K) record.getValue(index); List list = map.get(keyVal); if (list == null) { list = new ArrayList(); map.put(keyVal, list); } list.add(mapper.map(record)); } return map; } @Override public final Map> intoGroups(Field[] keys) { if (keys == null) { keys = new Field[0]; } Map> map = new LinkedHashMap>(); for (R record : this) { RecordImpl key = new RecordImpl(keys); for (Field field : keys) { Utils.copyValue(key, field, record, field); } Result result = map.get(key); if (result == null) { result = new ResultImpl(configuration(), this.fields); map.put(key, result); } result.add(record); } return map; } @Override public final Map> intoGroups(Field[] keys, Class type) { return intoGroups(keys, Utils.configuration(this).recordMapperProvider().provide(fields, type)); } @Override public final Map> intoGroups(Field[] keys, RecordMapper mapper) { if (keys == null) { keys = new Field[0]; } Map> map = new LinkedHashMap>(); for (R record : this) { RecordImpl key = new RecordImpl(keys); for (Field field : keys) { Utils.copyValue(key, field, record, field); } List list = map.get(key); if (list == null) { list = new ArrayList(); map.put(key, list); } list.add(mapper.map(record)); } return map; } @Override public final Map> intoGroups(Table table) { Map> map = new LinkedHashMap>(); for (R record : this) { S key = record.into(table); Result result = map.get(key); if (result == null) { result = new ResultImpl(configuration(), this.fields); map.put(key, result); } result.add(record); } return map; } @Override public final Map> intoGroups(Table table, Class type) { return intoGroups(table, Utils.configuration(this).recordMapperProvider().provide(fields, type)); } @Override public final Map> intoGroups(Table table, RecordMapper mapper) { Map> map = new LinkedHashMap>(); for (R record : this) { S key = record.into(table); List list = map.get(key); if (list == null) { list = new ArrayList(); map.put(key, list); } list.add(mapper.map(record)); } return map; } @Override public final Object[][] intoArray() { int size = size(); Object[][] array = new Object[size][]; for (int i = 0; i < size; i++) { array[i] = get(i).intoArray(); } return array; } @Override public final Object[] intoArray(int fieldIndex) { Class type = fields.fields[fieldIndex].getType(); List list = getValues(fieldIndex); return list.toArray((Object[]) Array.newInstance(type, list.size())); } @Override public final T[] intoArray(int fieldIndex, Class type) { return (T[]) Convert.convertArray(intoArray(fieldIndex), type); } @Override public final U[] intoArray(int fieldIndex, Converter converter) { return Convert.convertArray(intoArray(fieldIndex), converter); } @Override public final Object[] intoArray(String fieldName) { Class type = field(fieldName).getType(); List list = getValues(fieldName); return list.toArray((Object[]) Array.newInstance(type, list.size())); } @Override public final T[] intoArray(String fieldName, Class type) { return (T[]) Convert.convertArray(intoArray(fieldName), type); } @Override public final U[] intoArray(String fieldName, Converter converter) { return Convert.convertArray(intoArray(fieldName), converter); } @Override public final T[] intoArray(Field field) { return getValues(field).toArray((T[]) Array.newInstance(field.getType(), 0)); } @Override public final T[] intoArray(Field field, Class type) { return (T[]) Convert.convertArray(intoArray(field), type); } @Override public final U[] intoArray(Field field, Converter converter) { return Convert.convertArray(intoArray(field), converter); } @Override public final Set intoSet(int fieldIndex) { return new LinkedHashSet(getValues(fieldIndex)); } @Override public final Set intoSet(int fieldIndex, Class type) { return new LinkedHashSet(getValues(fieldIndex, type)); } @Override public final Set intoSet(int fieldIndex, Converter converter) { return new LinkedHashSet(getValues(fieldIndex, converter)); } @Override public final Set intoSet(String fieldName) { return new LinkedHashSet(getValues(fieldName)); } @Override public final Set intoSet(String fieldName, Class type) { return new LinkedHashSet(getValues(fieldName, type)); } @Override public final Set intoSet(String fieldName, Converter converter) { return new LinkedHashSet(getValues(fieldName, converter)); } @Override public final Set intoSet(Field field) { return new LinkedHashSet(getValues(field)); } @Override public final Set intoSet(Field field, Class type) { return new LinkedHashSet(getValues(field, type)); } @Override public final Set intoSet(Field field, Converter converter) { return new LinkedHashSet(getValues(field, converter)); } @Override public final Result into(Field... f) { Result result = new ResultImpl(Utils.configuration(this), f); for (Record record : this) result.add(record.into(f)); return result; } // [jooq-tools] START [into-fields] /**/@Override public final Result> into(Field field1) { return (Result) into(new Field[] { field1 }); } /**/@Override public final Result> into(Field field1, Field field2) { return (Result) into(new Field[] { field1, field2 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3) { return (Result) into(new Field[] { field1, field2, field3 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4) { return (Result) into(new Field[] { field1, field2, field3, field4 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5) { return (Result) into(new Field[] { field1, field2, field3, field4, field5 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19, Field field20) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19, field20 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19, Field field20, Field field21) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19, field20, field21 }); } /**/@Override public final Result> into(Field field1, Field field2, Field field3, Field field4, Field field5, Field field6, Field field7, Field field8, Field field9, Field field10, Field field11, Field field12, Field field13, Field field14, Field field15, Field field16, Field field17, Field field18, Field field19, Field field20, Field field21, Field field22) { return (Result) into(new Field[] { field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11, field12, field13, field14, field15, field16, field17, field18, field19, field20, field21, field22 }); } // [jooq-tools] END [into-fields] @Override public final List into(Class type) { List list = new ArrayList(size()); RecordMapper mapper = Utils.configuration(this).recordMapperProvider().provide(fields, type); for (R record : this) { list.add(mapper.map(record)); } return list; } @Override public final Result into(Table table) { Result list = new ResultImpl(configuration(), table.fields()); for (R record : this) { list.add(record.into(table)); } return list; } @Override public final > H into(H handler) { for (R record : this) { handler.next(record); } return handler; } @Override public final ResultSet intoResultSet() { return new MockResultSet(this); } @Override public final List map(RecordMapper mapper) { List result = new ArrayList(); for (R record : this) { result.add(mapper.map(record)); } return result; } @Override public final > Result sortAsc(Field field) { return sortAsc(field, new NaturalComparator()); } @Override public final Result sortAsc(int fieldIndex) { return sortAsc(fieldIndex, new NaturalComparator()); } @Override public final Result sortAsc(String fieldName) { return sortAsc(fieldName, new NaturalComparator()); } @Override public final Result sortAsc(Field field, Comparator comparator) { return sortAsc(indexOrFail(fieldsRow(), field), comparator); } @Override public final Result sortAsc(int fieldIndex, Comparator comparator) { return sortAsc(new RecordComparator(fieldIndex, comparator)); } @Override public final Result sortAsc(String fieldName, Comparator comparator) { return sortAsc(indexOrFail(fieldsRow(), fieldName), comparator); } @Override public final Result sortAsc(Comparator comparator) { Collections.sort(this, comparator); return this; } @Override public final > Result sortDesc(Field field) { return sortAsc(field, Collections.reverseOrder(new NaturalComparator())); } @Override public final Result sortDesc(int fieldIndex) { return sortAsc(fieldIndex, Collections.reverseOrder(new NaturalComparator())); } @Override public final Result sortDesc(String fieldName) { return sortAsc(fieldName, Collections.reverseOrder(new NaturalComparator())); } @Override public final Result sortDesc(Field field, Comparator comparator) { return sortAsc(field, Collections.reverseOrder(comparator)); } @Override public final Result sortDesc(int fieldIndex, Comparator comparator) { return sortAsc(fieldIndex, Collections.reverseOrder(comparator)); } @Override public final Result sortDesc(String fieldName, Comparator comparator) { return sortAsc(fieldName, Collections.reverseOrder(comparator)); } @Override public final Result sortDesc(Comparator comparator) { return sortAsc(Collections.reverseOrder(comparator)); } @Override public final Result intern(Field... f) { return intern(fields.indexesOf(f)); } @Override public final Result intern(int... fieldIndexes) { for (int fieldIndex : fieldIndexes) { if (fields.fields[fieldIndex].getType() == String.class) { for (Record record : this) { ((AbstractRecord) record).intern0(fieldIndex); } } } return this; } @Override public final Result intern(String... fieldNames) { return intern(fields.indexesOf(fieldNames)); } /** * A comparator for records, wrapping another comparator for <T> */ private static class RecordComparator implements Comparator { private final Comparator comparator; private final int fieldIndex; RecordComparator(int fieldIndex, Comparator comparator) { this.fieldIndex = fieldIndex; this.comparator = comparator; } @Override public int compare(R record1, R record2) { return comparator.compare((T) record1.getValue(fieldIndex), (T) record2.getValue(fieldIndex)); } } /** * A natural comparator */ private static class NaturalComparator> implements Comparator { @Override public int compare(T o1, T o2) { if (o1 == null && o2 == null) { return 0; } else if (o1 == null) { return -1; } else if (o2 == null) { return 1; } return o1.compareTo(o2); } } // ------------------------------------------------------------------------- // XXX Object API // ------------------------------------------------------------------------- @Override public String toString() { return format(); } @Override public int hashCode() { return records.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof ResultImpl) { ResultImpl other = (ResultImpl) obj; return records.equals(other.records); } return false; } // ------------------------------------------------------------------------- // XXX: List API // ------------------------------------------------------------------------- @Override public final int size() { return records.size(); } @Override public final boolean contains(Object o) { return records.contains(o); } @Override public final Object[] toArray() { return records.toArray(); } @Override public final T[] toArray(T[] a) { return records.toArray(a); } @Override public final boolean add(R e) { return records.add(e); } @Override public final boolean remove(Object o) { return records.remove(o); } @Override public final boolean containsAll(Collection c) { return records.containsAll(c); } @Override public final boolean addAll(Collection c) { return records.addAll(c); } @Override public final boolean addAll(int index, Collection c) { return records.addAll(index, c); } @Override public final boolean removeAll(Collection c) { return records.removeAll(c); } @Override public final boolean retainAll(Collection c) { return records.retainAll(c); } @Override public final void clear() { records.clear(); } @Override public final R get(int index) { return records.get(index); } @Override public final R set(int index, R element) { return records.set(index, element); } @Override public final void add(int index, R element) { records.add(index, element); } @Override public final R remove(int index) { return records.remove(index); } @Override public final int indexOf(Object o) { return records.indexOf(o); } @Override public final int lastIndexOf(Object o) { return records.lastIndexOf(o); } @Override public final Iterator iterator() { return records.iterator(); } @Override public final ListIterator listIterator() { return records.listIterator(); } @Override public final ListIterator listIterator(int index) { return records.listIterator(index); } @Override public final List subList(int fromIndex, int toIndex) { return records.subList(fromIndex, toIndex); } }