All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openlca.proto.io.output.Refs Maven / Gradle / Ivy

The newest version!
package org.openlca.proto.io.output;

import com.google.protobuf.Message;
import gnu.trove.map.hash.TLongObjectHashMap;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.NativeSql;
import org.openlca.core.model.Flow;
import org.openlca.core.model.ImpactCategory;
import org.openlca.core.model.Process;
import org.openlca.core.model.RefEntity;
import org.openlca.core.model.Version;
import org.openlca.core.model.descriptors.RootDescriptor;
import org.openlca.core.model.descriptors.Descriptor;
import org.openlca.core.model.descriptors.FlowDescriptor;
import org.openlca.core.model.descriptors.ImpactDescriptor;
import org.openlca.core.model.descriptors.ProcessDescriptor;
import org.openlca.proto.ProtoRef;
import org.openlca.util.Categories;
import org.openlca.util.Strings;

/**
 * A utility class for creating data set references.
 */
public final class Refs {

	private Refs() {
	}

	public static ProtoRef.Builder refOf(RefEntity e) {
		var proto = ProtoRef.newBuilder();
		if (e == null)
			return proto;
		proto.setType(Out.protoTypeOf(e));
		Out.map(e, proto);

		if (e instanceof Flow flow) {

			// flow specific fields
			if (flow.flowType != null) {
				proto.setFlowType(Out.flowTypeOf(flow.flowType));
			}
			if (flow.location != null) {
				proto.setLocation(Strings.orEmpty(flow.location.code));
			}
			var refUnit = flow.getReferenceUnit();
			if (refUnit != null) {
				proto.setRefUnit(Strings.orEmpty(refUnit.name));
			}

			// process specific fields
		} else if (e instanceof Process process) {
			if (process.processType != null) {
				proto.setProcessType(Out.processTypeOf(process.processType));
			}
			if (process.quantitativeReference != null) {
				var refFlow = process.quantitativeReference.flow;
				if (refFlow != null) {
					proto.setFlowType(Out.flowTypeOf(refFlow.flowType));
				}
			}
			if (process.location != null) {
				proto.setLocation(Strings.orEmpty(process.location.code));
			}

			// impact specific fields
		} else if (e instanceof ImpactCategory impact) {
			proto.setRefUnit(Strings.orEmpty(impact.referenceUnit));
		}
		return proto;
	}

	public static ProtoRef.Builder refOf(Descriptor d, RefData refData) {
		var proto = refOf(d);
		if (d == null || refData == null)
			return proto;

		if (d instanceof RootDescriptor cd) {
			proto.setCategory(refData.categoryPathOf(cd.category));
		}

		if (d instanceof ProcessDescriptor pd) {
			if (pd.location != null) {
				proto.setLocation(refData.locationCodeOf(pd.location));
			}
		}

		if (d instanceof FlowDescriptor fd) {
			if (fd.location != null) {
				proto.setLocation(refData.locationCodeOf(fd.location));
			}
			proto.setRefUnit(refData.flowUnitOf(fd.refFlowPropertyId));
		}

		return proto;
	}

	public static ProtoRef.Builder refOf(Descriptor d) {
		var proto = ProtoRef.newBuilder();
		if (d == null)
			return proto;
		proto.setType(Out.protoTypeOf(d.type));
		map(d, proto);
		if (d instanceof FlowDescriptor fd) {
			if (fd.flowType != null) {
				proto.setFlowType(Out.flowTypeOf(fd.flowType));
			}
		} else if (d instanceof ProcessDescriptor pd) {
			if (pd.processType != null) {
				proto.setProcessType(Out.processTypeOf(pd.processType));
			}
			if (pd.flowType != null) {
				proto.setFlowType((Out.flowTypeOf(pd.flowType)));
			}
		} else if (d instanceof ImpactDescriptor id) {
			proto.setRefUnit(Strings.orEmpty(id.referenceUnit));
		}
		return proto;
	}

	private static void map(Descriptor d, Message.Builder proto) {
		if (d == null || proto == null)
			return;
		var fields = proto.getDescriptorForType().getFields();
		for (var field : fields) {
			switch (field.getName()) {
				case "id" -> Out.set(proto, field, d.refId);
				case "name" -> Out.set(proto, field, d.name);
				case "version" -> Out.set(proto, field, Version.asString(d.version));
				case "last_change" ->
					Out.set(proto, field, Out.dateTimeOf(d.lastChange));
				case "library" -> Out.set(proto, field, d.library);
			}
		}
	}

	/**
	 * Returns a new ref-data object for querying reference
	 * data from the database efficiently to build data set
	 * references. You should always reuse such a ref-data
	 * object when you want to build multiple references
	 * (and the data did not change in the meantime).
	 */
	public static RefData dataOf(IDatabase db) {
		return new RefData(db);
	}

	public static class RefData {

		private final IDatabase db;
		private Categories.PathBuilder categories;
		private TLongObjectHashMap flowUnits;
		private TLongObjectHashMap locationCodes;

		private RefData(IDatabase db) {
			this.db = db;
		}

		String categoryPathOf(Long categoryId) {
			if (categoryId == null)
				return "";
			if (categories == null) {
				categories = Categories.pathsOf(db);
			}
			return Strings.orEmpty(categories.pathOf(categoryId));
		}

		String locationCodeOf(Long locationId) {
			if (locationId == null)
				return "";
			if (locationCodes == null) {
				locationCodes = new TLongObjectHashMap<>();
				var query = "select id, code, name from tbl_locations";
				NativeSql.on(db).query(query, r -> {
					var locID = r.getLong(1);
					var code = r.getString(2);
					if (Strings.nullOrEmpty(code)) {
						code = r.getString(3);
					}
					if (Strings.notEmpty(code)) {
						locationCodes.put(locID, code);
					}
					return true;
				});
			}
			return Strings.orEmpty(locationCodes.get(locationId));
		}

		String flowUnitOf(long flowPropertyId) {
			if (flowUnits == null) {
				flowUnits = new TLongObjectHashMap<>();
				var query = "select fp.id, u.name" +
					"  from tbl_flow_properties fp" +
					"  inner join tbl_unit_groups ug" +
					"  on fp.f_unit_group = ug.id" +
					"  inner join tbl_units u" +
					"  on ug.f_reference_unit = u.id";
				NativeSql.on(db).query(query, r -> {
					long propID = r.getLong(1);
					var unit = r.getString(2);
					flowUnits.put(propID, unit);
					return true;
				});
			}
			return Strings.orEmpty(flowUnits.get(flowPropertyId));
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy