package org.openlca.core.database; import java.sql.SQLException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.openlca.core.model.Flow; import org.openlca.core.model.FlowType; import org.openlca.core.model.descriptors.FlowDescriptor; public class FlowDao extends CategorizedEntityDao<Flow, FlowDescriptor> { public FlowDao(IDatabase database) { super(Flow.class, FlowDescriptor.class, database); } @Override protected String[] getDescriptorFields() { return new String[] { "id", "ref_id", "name", "description", "version", "last_change", "f_category", "flow_type", "f_location", "f_reference_flow_property" }; } @Override protected FlowDescriptor createDescriptor(Object[] queryResult) { if (queryResult == null) return null; FlowDescriptor descriptor = super.createDescriptor(queryResult); if (queryResult[7] instanceof String) descriptor.setFlowType(FlowType.valueOf((String) queryResult[7])); descriptor.setLocation((Long) queryResult[8]); Long refProp = (Long) queryResult[9]; if (refProp != null) descriptor.setRefFlowPropertyId(refProp); return descriptor; } /** * Returns the processes where the given flow is an output. */ public Set<Long> getProviders(long flowId) { return getProcessIdsWhereUsed(flowId, false); } /** * Returns the processes where the given flow is an input. */ public Set<Long> getRecipients(long flowId) { return getProcessIdsWhereUsed(flowId, true); } public Set<Long> getUsed() { Set<Long> ids = new HashSet<>(); String query = "SELECT DISTINCT f_flow FROM tbl_exchanges"; try { NativeSql.on(database).query(query, (rs) -> { ids.add(rs.getLong("f_flow")); return true; }); return ids; } catch (Exception e) { DatabaseException.logAndThrow(log, "failed to load used flows", e); return Collections.emptySet(); } } public Set<Long> getReplacementCandidates(long flowId, FlowType type) { Set<Long> ids = new HashSet<>(); String query = "SELECT DISTINCT f_flow FROM tbl_flow_property_factors WHERE f_flow_property IN " + "(SELECT f_flow_property FROM tbl_flow_property_factors WHERE f_flow = " + flowId + ") " + "AND f_flow IN (SELECT DISTINCT id FROM tbl_flows WHERE flow_type = '" + type.name() + "')"; try { NativeSql.on(database).query(query, (rs) -> { ids.add(rs.getLong("f_flow")); return true; }); ids.remove(flowId); return ids; } catch (Exception e) { DatabaseException.logAndThrow(log, "failed to load replacement candidate flows for " + flowId, e); return Collections.emptySet(); } } public void replace(long oldId, long newId, boolean excludeExchangesWithProviders) { try { String statement = null; if (excludeExchangesWithProviders) { statement = "UPDATE tbl_exchanges SET f_flow = " + newId + " " + "WHERE f_flow = " + oldId + " AND f_default_provider IS NULL"; } else { statement = "UPDATE tbl_exchanges SET f_flow = " + newId + ", f_default_provider = null " + "WHERE f_flow = " + oldId; } NativeSql.on(database).runUpdate(statement); statement = "UPDATE tbl_impact_factors SET f_flow = " + newId + " WHERE f_flow = " + oldId; NativeSql.on(database).runUpdate(statement); } catch (Exception e) { DatabaseException.logAndThrow(log, "failed to replace flow " + oldId + " with " + newId, e); } } private Set<Long> getProcessIdsWhereUsed(long flowId, boolean input) { Set<Long> ids = new HashSet<>(); String query = "SELECT f_owner FROM tbl_exchanges WHERE f_flow = " + flowId + " AND is_input = " + (input ? 1 : 0); try { NativeSql.on(database).query(query, (rs) -> { ids.add(rs.getLong("f_owner")); return true; }); return ids; } catch (Exception e) { DatabaseException.logAndThrow(log, "failed to load processes for flow " + flowId, e); return Collections.emptySet(); } } public boolean hasReferenceFactor(long id) { return hasReferenceFactor(Collections.singleton(id)).get(id); } public Map<Long, Boolean> hasReferenceFactor(Set<Long> ids) { StringBuilder query = new StringBuilder(); query.append("SELECT id, f_reference_flow_property FROM tbl_flows "); query.append("WHERE id IN " + asSqlList(ids)); query.append(" AND f_reference_flow_property IN "); query.append("(SELECT f_flow_property FROM tbl_flow_property_factors WHERE tbl_flows.id = f_flow)"); Map<Long, Boolean> result = new HashMap<>(); for (long id : ids) result.put(id, false); try { NativeSql.on(database).query(query.toString(), (res) -> { result.put(res.getLong(1), res.getLong(2) != 0l); return true; }); } catch (SQLException e) { log.error("Error checking for reference factor existence", e); } return result; } }