/*************************************************************************
* *
* 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.analysis.Utils;
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.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;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DeliveredStrainWell extends PlateWell<DeliveredStrainWell> {
public static final String TABLE_NAME = "wells_delivered_strain";
protected static final DeliveredStrainWell INSTANCE = new DeliveredStrainWell();
public static DeliveredStrainWell 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"),
WELL(5, 4, "well"),
MSID(6, 5, "msid"),
COMPOSITION(7, 6, "composition"),
;
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<DeliveredStrainWell> fromResultSet(ResultSet resultSet) throws SQLException {
List<DeliveredStrainWell> 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 well = resultSet.getString(DB_FIELD.WELL.getOffset());
String msid = resultSet.getString(DB_FIELD.MSID.getOffset());
String composition = resultSet.getString(DB_FIELD.COMPOSITION.getOffset());
results.add(new DeliveredStrainWell(id, plateId, plateRow, plateColumn, well, msid, composition));
}
return results;
}
// Insert/Update
protected void bindInsertOrUpdateParameters(
PreparedStatement stmt, Integer plateId, Integer plateRow, Integer plateColumn,
String well, String msid, String composition) 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.WELL.getInsertUpdateOffset(), well);
stmt.setString(DB_FIELD.MSID.getInsertUpdateOffset(), msid);
stmt.setString(DB_FIELD.COMPOSITION.getInsertUpdateOffset(), composition);
}
@Override
protected void bindInsertOrUpdateParameters(PreparedStatement stmt, DeliveredStrainWell dsw)
throws SQLException {
bindInsertOrUpdateParameters(stmt, dsw.getPlateId(), dsw.getPlateRow(), dsw.getPlateColumn(),
dsw.getWell(), dsw.getMsid(), dsw.getComposition());
}
public DeliveredStrainWell insert(
DB db, Integer plateId, Integer plateRow, Integer plateColumn,
String well, String msid, String composition) throws SQLException, IOException {
return INSTANCE.insert(db, new DeliveredStrainWell(null, plateId, plateRow, plateColumn, well, msid, composition));
}
// Parsing/loading
public List<DeliveredStrainWell> insertFromPlateComposition(DB db, PlateCompositionParser parser, Plate p)
throws SQLException, IOException {
List<DeliveredStrainWell> results = new ArrayList<>();
Map<Pair<String, String>, String> featuresTable = parser.getCompositionTables().get("well");
/* The composition tables are usually constructed with well coordinates as the X and Y axes. Amyris strain plates,
* however, have the combined well coordinates in the first column and the msid/composition in related columns.
* We'll collect the features in each row by traversing the per-cell entries in the parser's table and merging on
* the first coordinate component. */
Map<Pair<Integer, Integer>, Map<String, String>> wellToFeaturesMap = new HashMap<>();
for (Map.Entry<Pair<String, String>, String> entry : featuresTable.entrySet()) {
String wellCoordinates = entry.getKey().getLeft();
String featureName = entry.getKey().getRight();
String featureValue = entry.getValue();
Pair<Integer, Integer> coordinates = Utils.parsePlateCoordinates(wellCoordinates);
Map<String, String> featuresForWell = wellToFeaturesMap.get(coordinates);
if (featuresForWell == null){
featuresForWell = new HashMap<>();
wellToFeaturesMap.put(coordinates, featuresForWell);
}
if (featuresForWell.containsKey(featureName)) {
throw new RuntimeException(
String.format("Found duplicate feature %s for well %s", wellCoordinates, featureName));
}
featuresForWell.put(featureName, featureValue);
// Also save the original well coordinates string.
featuresForWell.put("well", wellCoordinates);
}
List<Map.Entry<Pair<Integer, Integer>, Map<String, String>>> sortedEntries =
new ArrayList<>(wellToFeaturesMap.entrySet());
Collections.sort(sortedEntries, new Comparator<Map.Entry<Pair<Integer, Integer>, Map<String, String>>>() {
@Override
public int compare(Map.Entry<Pair<Integer, Integer>, Map<String, String>> o1,
Map.Entry<Pair<Integer, Integer>, Map<String, String>> o2) {
return o1.getKey().compareTo(o2.getKey());
}
});
for (Map.Entry<Pair<Integer, Integer>, Map<String, String>> entry : sortedEntries) {
Pair<Integer, Integer> coords = entry.getKey();
Map<String, String> attrs = entry.getValue();
DeliveredStrainWell s = INSTANCE.insert(db, p.getId(), coords.getLeft(), coords.getRight(),
attrs.get("well"), attrs.get("msid"), attrs.get("composition"));
results.add(s);
}
return results;
}
private String well;
private String msid;
private String composition;
private DeliveredStrainWell() { }
protected DeliveredStrainWell(Integer id, Integer plateId, Integer plateRow, Integer plateColumn,
String well, String msid, String composition) {
this.id = id;
this.plateId = plateId;
this.plateRow = plateRow;
this.plateColumn = plateColumn;
this.well = well;
this.msid = msid;
this.composition = composition;
}
public String getWell() {
return well;
}
public void setWell(String well) {
this.well = well;
}
public String getMsid() {
return msid;
}
public void setMsid(String msid) {
this.msid = msid;
}
public String getComposition() {
return composition;
}
public void setComposition(String composition) {
this.composition = composition;
}
}