package org.aksw.sparqlify.core.sparql;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.UUID;
import org.aksw.jena_sparql_api.views.E_RdfTerm;
import org.aksw.sparqlify.core.MakeNodeValue;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.engine.binding.BindingHashMap;
import org.apache.jena.sparql.engine.binding.BindingMap;
import org.apache.jena.sparql.expr.NodeValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.RowMapper;
public class RowMapperSparqlifyBinding
implements RowMapper<Binding>
{
private static final Logger logger = LoggerFactory.getLogger(RowMapperSparqlifyBinding.class);
//private long nextRowId;
private Var rowIdVar;
public RowMapperSparqlifyBinding()
{
this("rowId");
}
public RowMapperSparqlifyBinding(String rowIdName)
{
this.rowIdVar = rowIdName == null ? null : Var.alloc(rowIdName);
}
@Override
public Binding mapRow(ResultSet rs, int rowId) {
Binding result = _map(rs, rowId, rowIdVar);
return result;
}
public static Binding _map(ResultSet rs, long rowId, Var rowIdVar) {
Binding result;
try {
result = map(rs, rowId, rowIdVar);
} catch(Exception e) {
throw new RuntimeException(e);
}
return result;
}
public static boolean addAttr(BindingHashMap binding, int i, String colName, Object colValue) {
NodeValue nodeValue;
// NOTE Char right padding is handled as a special expression (similar to urlEncode)
// String colType = meta.getColumnTypeName(i);
//
// //System.out.println(colValue == null ? "null" : colValue.getClass());
//
// // TODO: Make datatype serialization configurable
// if(isCharType(colType)) {
// if(colValue == null) {
// nodeValue = null;
// } else {
// int displaySize = meta.getPrecision(i);
// int scale = meta.getScale(i);
// String tmp = "" + colValue;
// String v = StringUtils.rightPad(tmp, displaySize);
// nodeValue = NodeValue.makeString(v);
// }
// }
// else
if(colValue instanceof Date) {
String tmp = colValue.toString();
nodeValue = NodeValue.makeDate(tmp);
}
else if(colValue instanceof Timestamp) {
String tmp = colValue.toString();
String val = tmp.replace(' ', 'T');
nodeValue = NodeValue.makeDateTime(val);
} else if(colValue instanceof UUID) {
nodeValue = NodeValue.makeString(colValue.toString());
} else {
try {
nodeValue = MakeNodeValue.makeNodeValue(colValue);
} catch (Exception e) {
logger.error("TODO: Handle unknown column type for " + colValue + " type: " + colValue.getClass());
nodeValue = null;
//throw new RuntimeException(e);
}
}
if(nodeValue == null) {
return true;
//continue;
}
if(nodeValue.equals(E_RdfTerm.TYPE_ERROR)) {
return true;
//continue;
}
// if(nodeValue.isDateTime()) {
// XSDDateTime val = nodeValue.getDateTime();
// String str = val.timeLexicalForm();
// String b = val.toString();
//
// System.out.println("foo");
// }
Node node = nodeValue.asNode();
// FIXME We also add bindings that enable us to reference the columns by their index
// However, indexes and column-names are in the same namespace here, so there might be clashes
Var indexVar = Var.alloc("" + i);
binding.add(indexVar, node);
Var colVar = Var.alloc(colName);
if(!binding.contains(colVar)) {
binding.add(colVar, node);
}
return false;
}
public static Binding map(ResultSet rs, long rowId, Var rowIdVar) throws SQLException {
// OPTIMIZE refactor these to attributes
//NodeExprSubstitutor substitutor = new NodeExprSubstitutor(sparqlVarMap);
BindingHashMap binding = new BindingHashMap();
ResultSetMetaData meta = rs.getMetaData();
/*
for(int i = 1; i <= meta.getColumnCount(); ++i) {
binding.add(Var.alloc("" + i), node)
}*/
// Substitute the variables in the expressions
for(int i = 1; i <= meta.getColumnCount(); ++i) {
String colName = meta.getColumnLabel(i);
Object colValue = rs.getObject(i);
boolean skip = addAttr(binding, i, colName, colValue);
if(skip) {
continue;
}
}
// Additional "virtual" columns
// FIXME Ideally this should be part of a class "ResultSetExtend" that extends a result set with additional columns
if(rowIdVar != null) {
Node node = NodeValue.makeInteger(rowId).asNode();
binding.add(rowIdVar, node);
}
return binding;
}
}