/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.datasource.jdbc;
import com.google.common.collect.Lists;
import org.obiba.magma.Value;
import org.obiba.magma.Variable;
import org.obiba.magma.VariableEntity;
import org.obiba.magma.type.DateTimeType;
import org.obiba.magma.type.LocaleType;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;
/**
* A "line" can be transformed in one or multiple SQL lines.
*/
class JdbcLine {
private final boolean multilines;
@NotNull
private final VariableEntity entity;
private final List<String> columnNames = Lists.newArrayList();
private final List<Value> values = Lists.newArrayList();
private final JdbcValueTable valueTable;
JdbcLine(@NotNull VariableEntity entity, JdbcValueTable valueTable) {
this.entity = entity;
this.valueTable = valueTable;
this.multilines = valueTable.isMultilines();
initialize();
}
void setValue(Variable variable, Value value) {
setValue(getVariableSqlName(variable), value);
}
List<String> getColumnNames() {
return columnNames;
}
List<List<Object>> getLines() {
if (multilines) {
return getMultipleLines();
} else {
List<List<Object>> lines = Lists.newArrayList();
lines.add(getSingleLine());
return lines;
}
}
int size() {
return getColumnNames().size();
}
//
// Private methods
//
private void initialize() {
Value timestamp = DateTimeType.get().now();
if (valueTable.hasValueSet(entity)) {
if (valueTable.hasUpdatedTimestampColumn()) {
setValue(valueTable.getUpdatedTimestampColumnName(), timestamp);
}
} else {
if (valueTable.hasCreatedTimestampColumn()) {
setValue(valueTable.getCreatedTimestampColumnName(), timestamp);
}
if (valueTable.hasUpdatedTimestampColumn()) {
setValue(valueTable.getUpdatedTimestampColumnName(), timestamp);
}
}
}
/**
* Convert each {@link Value} into a SQL value for a single line (then sequences are turned into CSV strings).
* @return
*/
private List<Object> getSingleLine() {
return values.stream().map(this::toColumnValue).collect(Collectors.toList());
}
private void setValue(String columnName, Value value) {
columnNames.add(columnName);
values.add(value);
}
private String getVariableSqlName(Variable variable) {
return valueTable.getVariableSqlName(variable.getName());
}
private Object toColumnValue(Value value) {
Object columnValue = null;
if(!value.isNull()) {
if(value.isSequence()) {
columnValue = value.toString();
} else {
columnValue = value.getValue();
// Persist some objects as strings.
if(value.getValueType() == LocaleType.get() || value.getValueType().isGeo()) {
columnValue = value.toString();
}
}
}
return columnValue;
}
public List<List<Object>> getMultipleLines() {
List<List<Object>> lines = Lists.newArrayList();
// first detect the longest value sequence
int length = values.stream().mapToInt(v -> v.isSequence() ? v.asSequence().getSize() : 1).max().orElse(1);
for (int i=0; i<length ; i++) {
lines.add(getMultipleLinesAt(i));
}
return lines;
}
private List<Object> getMultipleLinesAt(int position) {
List<Object> line = Lists.newArrayListWithExpectedSize(columnNames.size());
for (Value value : values) {
Value valueAt = value;
if (value.isSequence()) {
if (position < value.asSequence().getSize()) {
valueAt = value.asSequence().get(position);
} else {
valueAt = value.getValueType().nullValue();
}
}
line.add(toColumnValue(valueAt));
}
return line;
}
}