dnet-docker/dnet-app/libs/dnet-mdstore-postgres/src/main/java/eu/dnetlib/common/mdstores/backends/sql/MDStoreSqlBackend.java

148 lines
5.3 KiB
Java

package eu.dnetlib.common.mdstores.backends.sql;
import java.sql.Timestamp;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import eu.dnetlib.common.mdstores.MDStoreBackend;
import eu.dnetlib.domain.mdstore.MDStore;
import eu.dnetlib.domain.mdstore.MDStoreVersion;
import eu.dnetlib.domain.mdstore.records.MetadataRecord;
import eu.dnetlib.domain.mdstore.records.MetadataRecord.MetadataRecordEncoding;
import eu.dnetlib.domain.mdstore.records.Provenance;
import eu.dnetlib.errors.MDStoreManagerException;
import jakarta.transaction.Transactional;
public class MDStoreSqlBackend implements MDStoreBackend {
private final JdbcTemplate jdbcTemplate;
private final String databaseUrl;
public MDStoreSqlBackend(final String url, final String username, final String password) {
final DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
this.jdbcTemplate = new JdbcTemplate(ds, true);
this.databaseUrl = url;
}
@Override
public void completeNewMDStore(final MDStore mdstore) {
mdstore.getParams().put("databaseUrl", this.databaseUrl);
}
@Override
public void completeNewMDStoreVersion(final MDStoreVersion version) {
version.getParams().put("databaseUrl", this.databaseUrl);
version.getParams().put("table", asTableName(version.getId()));
}
@Override
public void delete(final MDStore mdstore) throws MDStoreManagerException {
final String table = asTableName(mdstore.getId());
final String vCond = table + "-" + "%";
final List<String> toDelete =
this.jdbcTemplate.queryForList("select tablename FROM pg_tables WHERE tablename = ? OR tablename like ?", String.class, table, vCond);
toDelete.forEach(t -> this.jdbcTemplate.execute("drop table if exists " + t));
}
@Override
public void delete(final MDStoreVersion version) throws MDStoreManagerException {
this.jdbcTemplate.execute("drop table if exists " + asTableName(version.getId()));
}
@Override
public List<MetadataRecord> listEntries(final MDStoreVersion version, final long limit) throws MDStoreManagerException {
return this.jdbcTemplate.query("select * from " + asTableName(version.getId()) + " limit ?", mdstoreMapper(), limit);
}
@Override
@Transactional
public void saveRecords(final MDStoreVersion version, final Stream<MetadataRecord> inputStream) {
final String table = asTableName(version.getId());
createTableIfMissing(table);
final String sql = "insert into " + table + " " +
"(id, originalid, body, dsid, dsname, dsprefix, dateofcollection, dateoftransformation) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?) " +
"ON CONFLICT (id) DO UPDATE SET " +
"(originalid, body, dsid, dsname, dsprefix, dateofcollection, dateoftransformation) = " +
"(EXCLUDED.originalid, EXCLUDED.body, EXCLUDED.dsid, EXCLUDED.dsname, EXCLUDED.dsprefix, EXCLUDED.dateofcollection, EXCLUDED.dateoftransformation)";
inputStream.forEach(r -> this.jdbcTemplate.update(sql, r.getId(), r.getOriginalId(), r.getBody(), r.getProvenance().getDatasourceId(), r.getProvenance()
.getDatasourceName(), r.getProvenance().getNsPrefix(), r.getDateOfCollection(), r.getDateOfTransformation()));
}
private void createTableIfMissing(final String table) {
this.jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS " + table + " ("
+ "id text PRIMARY KEY, "
+ "originalid text NOT NULL, "
+ "body text NOT NULL, "
+ "dsid text, "
+ "dsname text, "
+ "dsprefix char(12), "
+ "dateofcollection timestamp NOT NULL, "
+ "dateoftransformation timestamp"
+ ")");
}
@Override
public Stream<MetadataRecord> streamEntries(final MDStoreVersion version) throws MDStoreManagerException {
return this.jdbcTemplate.queryForStream("select * from " + asTableName(version.getId()), mdstoreMapper());
}
@Override
public Set<String> fixInconsistencies(final boolean delete) throws MDStoreManagerException {
// TODO (LOW PRIORITY) Auto-generated method stub
return null;
}
@Override
public long countRecords(final String versionId) {
final Long res = this.jdbcTemplate.queryForObject("select count(*) from " + asTableName(versionId), Long.class);
return res != null ? res : 0;
}
private static String asTableName(final String id) {
// It should prevents from SQL Injection
if (id.matches("^[a-zA-Z0-9\\-]+$")) { return id.replace('-', '_').toLowerCase(); }
throw new IllegalArgumentException("Invalid mdId: " + id);
}
private RowMapper<MetadataRecord> mdstoreMapper() {
return (rs, rowNum) -> {
final MetadataRecord mr = new MetadataRecord();
mr.setId(rs.getString("id"));
mr.setOriginalId(rs.getString("originalid"));
mr.setBody(rs.getString("body"));
mr.setProvenance(new Provenance(rs.getString("dsid"), rs.getString("dsname"), rs.getString("dsprefix")));
mr.setEncoding(MetadataRecordEncoding.XML);
final Timestamp t1 = rs.getTimestamp("dateofcollection");
final Timestamp t2 = rs.getTimestamp("dateoftransformation");
if (t1 != null) {
mr.setDateOfCollection(t1.toLocalDateTime());
}
if (t2 != null) {
mr.setDateOfCollection(rs.getTimestamp("dateoftransformation").toLocalDateTime());
}
return mr;
};
}
}