package edu.washington.escience.myria.column.builder;
import java.nio.BufferOverflowException;
import java.nio.LongBuffer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;
import org.joda.time.DateTime;
import com.almworks.sqlite4java.SQLiteException;
import com.almworks.sqlite4java.SQLiteStatement;
import com.google.common.base.Preconditions;
import edu.washington.escience.myria.Type;
import edu.washington.escience.myria.column.DateTimeColumn;
import edu.washington.escience.myria.column.mutable.DateTimeMutableColumn;
import edu.washington.escience.myria.proto.DataProto.ColumnMessage;
import edu.washington.escience.myria.proto.DataProto.DateTimeColumnMessage;
import edu.washington.escience.myria.storage.TupleBatch;
import edu.washington.escience.myria.storage.TupleUtils;
import edu.washington.escience.myria.util.MyriaUtils;
/**
* A column of Date values.
*
*/
public final class DateTimeColumnBuilder extends ColumnBuilder<DateTime> {
/**
* The internal representation of the data.
* */
private final DateTime[] data;
/** Number of elements in this column. */
private int numDates;
/**
* If the builder has built the column.
* */
private boolean built = false;
/** Constructs an empty column that can hold up to TupleBatch.BATCH_SIZE elements. */
public DateTimeColumnBuilder() {
numDates = 0;
data = new DateTime[TupleUtils.getBatchSize(Type.DATETIME_TYPE)];
}
/**
* copy.
*
* @param numDates the actual num strings in the data
* @param data the underlying data
* */
private DateTimeColumnBuilder(final DateTime[] data, final int numDates) {
this.numDates = numDates;
this.data = data;
}
/**
* Constructs a DateColumn by deserializing the given ColumnMessage.
*
* @param message a ColumnMessage containing the contents of this column.
* @param numTuples num tuples in the column message
* @return the built column
*/
public static DateTimeColumn buildFromProtobuf(final ColumnMessage message, final int numTuples) {
Preconditions.checkArgument(
message.getType().ordinal() == ColumnMessage.Type.DATETIME_VALUE,
"Trying to construct DateColumn from non-DATE ColumnMessage %s",
message.getType());
Preconditions.checkArgument(message.hasDateColumn(), "ColumnMessage is missing DateColumn");
final DateTimeColumnMessage dateColumn = message.getDateColumn();
DateTime[] newData = new DateTime[numTuples];
LongBuffer data = dateColumn.getData().asReadOnlyByteBuffer().asLongBuffer();
for (int i = 0; i < numTuples; i++) {
newData[i] = new DateTime(data.get());
}
return new DateTimeColumnBuilder(newData, numTuples).build();
}
@Override
public DateTimeColumnBuilder appendDateTime(final DateTime value) throws BufferOverflowException {
Preconditions.checkState(
!built, "No further changes are allowed after the builder has built the column.");
Objects.requireNonNull(value, "value");
if (numDates >= TupleUtils.getBatchSize(Type.DATETIME_TYPE)) {
throw new BufferOverflowException();
}
data[numDates++] = value;
return this;
}
@Override
public Type getType() {
return Type.DATETIME_TYPE;
}
@Override
public DateTimeColumnBuilder appendFromJdbc(final ResultSet resultSet, final int jdbcIndex)
throws SQLException, BufferOverflowException {
Preconditions.checkState(
!built, "No further changes are allowed after the builder has built the column.");
return appendDateTime(new DateTime(resultSet.getTimestamp(jdbcIndex).getTime()));
}
@Override
public DateTimeColumnBuilder appendFromSQLite(final SQLiteStatement statement, final int index)
throws SQLiteException, BufferOverflowException {
Preconditions.checkState(
!built, "No further changes are allowed after the builder has built the column.");
return appendDateTime(new DateTime(statement.columnLong(index)));
}
@Override
public int size() {
return numDates;
}
@Override
public DateTimeColumn build() {
built = true;
return new DateTimeColumn(data, numDates);
}
@Override
public DateTimeMutableColumn buildMutable() {
built = true;
return new DateTimeMutableColumn(data, numDates);
}
@Override
public void replaceDateTime(final DateTime value, final int row)
throws IndexOutOfBoundsException {
Preconditions.checkState(
!built, "No further changes are allowed after the builder has built the column.");
Preconditions.checkElementIndex(row, numDates);
Preconditions.checkNotNull(value);
data[row] = value;
}
@Override
public DateTimeColumnBuilder expand(final int size) throws BufferOverflowException {
Preconditions.checkState(
!built, "No further changes are allowed after the builder has built the column.");
Preconditions.checkArgument(size >= 0);
if (numDates + size > data.length) {
throw new BufferOverflowException();
}
numDates += size;
return this;
}
@Override
public DateTimeColumnBuilder expandAll() {
Preconditions.checkState(
!built, "No further changes are allowed after the builder has built the column.");
numDates = data.length;
return this;
}
@Override
public DateTime getDateTime(final int row) {
Preconditions.checkElementIndex(row, numDates);
return data[row];
}
@Override
public DateTime getObject(final int row) {
return getDateTime(row);
}
@Deprecated
@Override
public DateTimeColumnBuilder appendObject(final Object value) throws BufferOverflowException {
Preconditions.checkState(
!built, "No further changes are allowed after the builder has built the column.");
return appendDateTime((DateTime) MyriaUtils.ensureObjectIsValidType(value));
}
@Override
public DateTimeColumnBuilder forkNewBuilder() {
DateTime[] newData = new DateTime[data.length];
System.arraycopy(data, 0, newData, 0, numDates);
return new DateTimeColumnBuilder(newData, numDates);
}
}