/*
* ToroDB
* Copyright © 2014 8Kdata Technology (www.8kdata.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.torodb.backend.d2r;
import com.google.common.base.Preconditions;
import com.torodb.backend.DataTypeProvider;
import com.torodb.backend.ErrorHandler;
import com.torodb.backend.ErrorHandler.Context;
import com.torodb.backend.InternalField;
import com.torodb.backend.MetaDataReadInterface;
import com.torodb.backend.SqlHelper;
import com.torodb.backend.converters.jooq.DataTypeForKv;
import com.torodb.backend.tables.MetaDocPartTable;
import com.torodb.backend.tables.records.MetaDocPartRecord;
import com.torodb.core.d2r.DocPartResult;
import com.torodb.core.d2r.DocPartResultRow;
import com.torodb.core.d2r.IllegalDocPartRowException;
import com.torodb.core.transaction.metainf.FieldType;
import com.torodb.core.transaction.metainf.MetaDocPart;
import com.torodb.kvdocument.values.KvValue;
import org.jooq.Converter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
public class ResultSetDocPartResult implements DocPartResult {
private final MetaDataReadInterface metaDataReadInterface;
private final DataTypeProvider dataTypeProvider;
private final ErrorHandler errorHandler;
private final MetaDocPart metaDocPart;
private final ResultSet rs;
/**
* true iff {@link ResultSet#next() rs.next()} must be called before use the result set.
*/
private boolean lastRowConsumed = true;
private boolean hasNext = false;
private final SqlHelper sqlHelper;
public ResultSetDocPartResult(MetaDataReadInterface metaDataReadInterface,
DataTypeProvider dataTypeProvider, ErrorHandler errorHandler,
MetaDocPart metaDocPart, ResultSet rs, SqlHelper sqlHelper) {
this.metaDataReadInterface = metaDataReadInterface;
this.dataTypeProvider = dataTypeProvider;
this.errorHandler = errorHandler;
this.metaDocPart = metaDocPart;
this.rs = rs;
this.sqlHelper = sqlHelper;
}
@Override
public MetaDocPart getMetaDocPart() {
return metaDocPart;
}
@Override
public boolean hasNext() {
if (lastRowConsumed) {
lastRowConsumed = false;
try {
hasNext = rs.next();
} catch (SQLException sqlException) {
throw errorHandler.handleException(Context.FETCH, sqlException);
}
}
return hasNext;
}
@Override
public DocPartResultRow next() {
Preconditions.checkState(hasNext());
ResultSetNewDocPartRow result = new ResultSetNewDocPartRow();
lastRowConsumed = true;
return result;
}
@Override
public void close() {
try {
rs.close();
} catch (SQLException ex) {
throw errorHandler.handleException(Context.FETCH, ex);
}
}
private class ResultSetNewDocPartRow implements DocPartResultRow {
private final int did;
private final int rid;
private final int pid;
private final Integer seq;
private final int firstUserColumnIndex;
public ResultSetNewDocPartRow() throws IllegalDocPartRowException {
Collection<InternalField<?>> internalFields = metaDataReadInterface
.getInternalFields(metaDocPart);
Integer didTemp = null;
Integer pidTemp = null;
Integer ridTemp = null;
Integer seqTemp = null;
int columnIndex = 1;
MetaDocPartTable<Object, MetaDocPartRecord<Object>> metaDocPartTable = metaDataReadInterface
.getMetaDocPartTable();
for (InternalField<?> internalField : internalFields) {
try {
if (internalField.isDid()) {
didTemp = metaDocPartTable.DID.getValue(rs, columnIndex);
} else if (internalField.isRid()) {
ridTemp = metaDocPartTable.RID.getValue(rs, columnIndex);
} else if (internalField.isPid()) {
pidTemp = metaDocPartTable.PID.getValue(rs, columnIndex);
} else if (internalField.isSeq()) {
seqTemp = metaDocPartTable.SEQ.getValue(rs, columnIndex);
}
} catch (SQLException sqlException) {
throw errorHandler.handleException(Context.FETCH, sqlException);
}
columnIndex++;
if (didTemp == null) {
throw new IllegalDocPartRowException(null, ridTemp, pidTemp, seqTemp,
"did was not found for doc part " + metaDocPart.getTableRef());
}
if (ridTemp == null) {
ridTemp = didTemp;
}
if (pidTemp == null) {
pidTemp = didTemp;
}
}
this.did = didTemp;
this.rid = ridTemp;
this.pid = pidTemp;
this.seq = seqTemp;
this.firstUserColumnIndex = columnIndex;
}
@Override
public int getDid() {
return did;
}
@Override
public int getRid() {
return rid;
}
@Override
public int getPid() {
return pid;
}
@Override
public Integer getSeq() {
return seq;
}
@Override
public KvValue<?> getUserValue(int fieldIndex, FieldType fieldType) {
Object databaseValue;
try {
databaseValue = sqlHelper
.getResultSetValue(fieldType, rs, fieldIndex + firstUserColumnIndex);
} catch (SQLException sqlException) {
throw errorHandler.handleException(Context.FETCH, sqlException);
}
if (databaseValue == null) {
return null;
}
DataTypeForKv<?> dataType = dataTypeProvider.getDataType(fieldType);
@SuppressWarnings("unchecked")
Converter<Object, KvValue<?>> converter = (Converter<Object, KvValue<?>>) dataType
.getConverter();
return converter.from(databaseValue);
}
}
}