/*************************************************************************
* *
* This file is part of the 20n/act project. *
* 20n/act enables DNA prediction for synthetic biology/bioengineering. *
* Copyright (C) 2017 20n Labs, Inc. *
* *
* Please direct all queries to act@20n.com. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* 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 com.act.lcms.db.model;
import com.act.lcms.db.io.DB;
import com.act.lcms.db.io.parser.PlateCompositionParser;
import org.apache.commons.lang3.tuple.Pair;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InductionWell extends PlateWell<InductionWell> {
public static final String TABLE_NAME = "wells_induction";
protected static final InductionWell INSTANCE = new InductionWell();
public static InductionWell getInstance() {
return INSTANCE;
}
private enum DB_FIELD implements DBFieldEnumeration {
ID(1, -1, "id"),
PLATE_ID(2, 1, "plate_id"),
PLATE_ROW(3, 2, "plate_row"),
PLATE_COLUMN(4, 3, "plate_column"),
MSID(5, 4, "msid"),
CHEMICAL_SOURCE(6, 5, "chemical_source"),
COMPOSITION(7, 6, "composition"),
CHEMICAL(8, 7, "chemical"),
STRAIN_SOURCE(9, 8, "strain_source"),
NOTE(10, 9, "note"),
GROWTH(11, 10, "growth"),
;
private final int offset;
private final int insertUpdateOffset;
private final String fieldName;
DB_FIELD(int offset, int insertUpdateOffset, String fieldName) {
this.offset = offset;
this.insertUpdateOffset = insertUpdateOffset;
this.fieldName = fieldName;
}
@Override
public int getOffset() {
return offset;
}
@Override
public int getInsertUpdateOffset() {
return insertUpdateOffset;
}
@Override
public String getFieldName() {
return fieldName;
}
@Override
public String toString() {
return this.fieldName;
}
public static String[] names() {
DB_FIELD[] values = DB_FIELD.values();
String[] names = new String[values.length];
for (int i = 0; i < values.length; i++) {
names[i] = values[i].getFieldName();
}
return names;
}
}
protected static final List<String> ALL_FIELDS = Collections.unmodifiableList(Arrays.asList(DB_FIELD.names()));
// id is auto-generated on insertion.
protected static final List<String> INSERT_UPDATE_FIELDS = INSTANCE.makeInsertUpdateFields();
@Override
public String getTableName() {
return TABLE_NAME;
}
@Override
public List<String> getAllFields() {
return ALL_FIELDS;
}
@Override
public List<String> getInsertUpdateFields() {
return INSERT_UPDATE_FIELDS;
}
protected static final String GET_BY_ID_QUERY = INSTANCE.makeGetByIDQuery();
@Override
protected String getGetByIDQuery() {
return GET_BY_ID_QUERY;
}
protected static final String GET_BY_PLATE_ID_QUERY = INSTANCE.makeGetByPlateIDQuery();
@Override
protected String getGetByPlateIDQuery() {
return GET_BY_PLATE_ID_QUERY;
}
protected static final String INSERT_QUERY = INSTANCE.makeInsertQuery();
@Override
public String getInsertQuery() {
return INSERT_QUERY;
}
protected static final String UPDATE_QUERY = INSTANCE.makeUpdateQuery();
@Override
public String getUpdateQuery() {
return UPDATE_QUERY;
}
@Override
protected List<InductionWell> fromResultSet(ResultSet resultSet) throws SQLException {
List<InductionWell> results = new ArrayList<>();
while (resultSet.next()) {
Integer id = resultSet.getInt(DB_FIELD.ID.getOffset());
Integer plateId = resultSet.getInt(DB_FIELD.PLATE_ID.getOffset());
Integer plateRow = resultSet.getInt(DB_FIELD.PLATE_ROW.getOffset());
Integer plateColumn = resultSet.getInt(DB_FIELD.PLATE_COLUMN.getOffset());
String msid = resultSet.getString(DB_FIELD.MSID.getOffset());
String chemicalSource = resultSet.getString(DB_FIELD.CHEMICAL_SOURCE.getOffset());
String composition = resultSet.getString(DB_FIELD.COMPOSITION.getOffset());
String chemical = resultSet.getString(DB_FIELD.CHEMICAL.getOffset());
String strainSource = resultSet.getString(DB_FIELD.STRAIN_SOURCE.getOffset());
String note = resultSet.getString(DB_FIELD.NOTE.getOffset());
Integer growth = resultSet.getInt(DB_FIELD.GROWTH.getOffset());
if (resultSet.wasNull()) {
growth = null;
}
results.add(new InductionWell(id, plateId, plateRow, plateColumn, msid, chemicalSource, composition,
chemical, strainSource, note, growth));
}
return results;
}
// Insert/Update
protected void bindInsertOrUpdateParameters(
PreparedStatement stmt, Integer plateId, Integer plateRow, Integer plateColumn,
String msid, String chemicalSource, String composition, String chemical, String strainSource,
String note, Integer growth) throws SQLException {
stmt.setInt(DB_FIELD.PLATE_ID.getInsertUpdateOffset(), plateId);
stmt.setInt(DB_FIELD.PLATE_ROW.getInsertUpdateOffset(), plateRow);
stmt.setInt(DB_FIELD.PLATE_COLUMN.getInsertUpdateOffset(), plateColumn);
stmt.setString(DB_FIELD.MSID.getInsertUpdateOffset(), msid);
stmt.setString(DB_FIELD.CHEMICAL_SOURCE.getInsertUpdateOffset(), chemicalSource);
stmt.setString(DB_FIELD.COMPOSITION.getInsertUpdateOffset(), composition);
stmt.setString(DB_FIELD.CHEMICAL.getInsertUpdateOffset(), chemical);
stmt.setString(DB_FIELD.STRAIN_SOURCE.getInsertUpdateOffset(), strainSource);
stmt.setString(DB_FIELD.NOTE.getInsertUpdateOffset(), note);
if (growth == null) {
stmt.setNull(DB_FIELD.GROWTH.getInsertUpdateOffset(), Types.INTEGER);
} else {
stmt.setInt(DB_FIELD.GROWTH.getInsertUpdateOffset(), growth);
}
}
@Override
protected void bindInsertOrUpdateParameters(PreparedStatement stmt, InductionWell sw) throws SQLException {
bindInsertOrUpdateParameters(stmt, sw.getPlateId(), sw.getPlateRow(), sw.getPlateColumn(),
sw.getMsid(), sw.getChemicalSource(), sw.getComposition(), sw.getChemical(), sw.getStrainSource(),
sw.getNote(), sw.getGrowth());
}
public InductionWell insert(
DB db, Integer plateId, Integer plateRow, Integer plateColumn,
String msid, String chemicalSource, String composition, String chemical, String strainSource,
String note, Integer growth) throws SQLException, IOException {
return INSTANCE.insert(db, new InductionWell(null, plateId, plateRow, plateColumn, msid, chemicalSource,
composition, chemical, strainSource, note, growth));
}
// Parsing/loading
// TODO: remove this once this growth specification is no longer used.
private static final Map<String, Integer> PLUS_MINUS_GROWTH_TO_INT = Collections.unmodifiableMap(
new HashMap<String, Integer>() {{
put("---", 0);
put("--", 1);
put("-", 2);
put("+", 3);
put("++", 4);
put("+++", 5);
}});
public List<InductionWell> insertFromPlateComposition(DB db, PlateCompositionParser parser, Plate p)
throws SQLException, IOException {
Map<String, String> plateAttributes = parser.getPlateProperties();
Map<Pair<String, String>, String> msids = parser.getCompositionTables().get("msid");
List<Pair<String, String>> sortedCoordinates = new ArrayList<>(msids.keySet());
Collections.sort(sortedCoordinates, new Comparator<Pair<String, String>>() {
// TODO: parse the values of these pairs as we read them so we don't need this silly comparator.
@Override
public int compare(Pair<String, String> o1, Pair<String, String> o2) {
if (o1.getKey().equals(o2.getKey())) {
return Integer.valueOf(Integer.parseInt(o1.getValue())).compareTo(Integer.parseInt(o2.getValue()));
}
return o1.getKey().compareTo(o2.getKey());
}
});
List<InductionWell> results = new ArrayList<>();
for (Pair<String, String> coords : sortedCoordinates) {
String msid = msids.get(coords);
if (msid == null || msid.isEmpty()) {
continue;
}
String chemicalSource = parser.getCompositionTables().get("chemical_source").get(coords);
String composition = parser.getCompositionTables().get("composition").get(coords);
String chemical = parser.getCompositionTables().get("chemical").get(coords);
String strainSource = parser.getCompositionTables().get("strain_source").get(coords);
String note = null;
if (parser.getCompositionTables().get("note") != null) {
note = parser.getCompositionTables().get("note").get(coords);
}
// TODO: ditch this when we start using floating point numbers for growth values.
Integer growth = null;
Map<Pair<String, String>, String> growthTable = parser.getCompositionTables().get("growth");
if (growthTable == null || growthTable.get(coords) == null) {
String plateGrowth = plateAttributes.get("growth");
if (plateGrowth != null) {
growth = Integer.parseInt(trimAndComplain(plateGrowth));
}
} else {
String growthStr = growthTable.get(coords);
if (PLUS_MINUS_GROWTH_TO_INT.containsKey(growthStr)) {
growth = PLUS_MINUS_GROWTH_TO_INT.get(growthStr);
} else {
growth = Integer.parseInt(growthStr); // If it's not using +/- format, it should be an integer from 1-5.
}
}
Pair<Integer, Integer> index = parser.getCoordinatesToIndices().get(coords);
InductionWell s = INSTANCE.insert(db, p.getId(), index.getLeft(), index.getRight(),
msid, chemicalSource, composition, chemical, strainSource, note, growth);
results.add(s);
}
return results;
}
public static String trimAndComplain(String val) {
String tval = val.trim();
if (!val.equals(tval)) {
System.err.format("WARNING: trimmed spurious whitespace from '%s'\n", val);
}
return tval;
}
private String msid;
private String chemicalSource;
private String composition;
private String chemical;
private String strainSource;
private String note;
private Integer growth;
private InductionWell() { }
protected InductionWell(Integer id, Integer plateId, Integer plateRow, Integer plateColumn, String msid,
String chemicalSource, String composition, String chemical, String strainSource,
String note, Integer growth) {
this.id = id;
this.plateId = plateId;
this.plateRow = plateRow;
this.plateColumn = plateColumn;
this.msid = msid;
this.chemicalSource = chemicalSource;
this.composition = composition;
this.chemical = chemical;
this.strainSource = strainSource;
this.note = note;
this.growth = growth;
}
public String getMsid() {
return msid;
}
public void setMsid(String msid) {
this.msid = msid;
}
public String getChemicalSource() {
return chemicalSource;
}
public void setChemicalSource(String chemicalSource) {
this.chemicalSource = chemicalSource;
}
public String getComposition() {
return composition;
}
public void setComposition(String composition) {
this.composition = composition;
}
public String getChemical() {
return chemical;
}
public void setChemical(String chemical) {
this.chemical = chemical;
}
public String getStrainSource() {
return strainSource;
}
public void setStrainSource(String strainSource) {
this.strainSource = strainSource;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public Integer getGrowth() {
return growth;
}
public void setGrowth(Integer growth) {
this.growth = growth;
}
}