Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server side plate type support #5143

Merged
merged 29 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ded56ba
plate type checkpoint
labkey-klum Jan 13, 2024
18899e8
Merge branch 'develop' into fb_plate_type_schema
labkey-klum Jan 15, 2024
a44b7fc
replace row/column inputs with PlateType
labkey-klum Jan 16, 2024
2e51006
merge from develop
labkey-klum Jan 16, 2024
d97fba5
plate type upgrade scripts
labkey-klum Jan 16, 2024
d5227fa
revert CSP change
labkey-klum Jan 16, 2024
d97c5d0
CreatePlateAction: pass optional plateSetId
labkey-nicka Jan 16, 2024
3795e25
Merge branch 'develop' into fb_plate_type_schema
labkey-nicka Jan 17, 2024
4bc5879
support for plate and plateSet IDs, schema changes
labkey-klum Jan 18, 2024
343b7ea
upgrade script changes, add description field to plate and plateSet t…
labkey-klum Jan 18, 2024
557aa83
Merge branch 'develop' into fb_plate_type_schema
labkey-klum Jan 18, 2024
5946bb0
use plate set ID for name expression
labkey-klum Jan 18, 2024
4ca6a15
Name, Description support
labkey-nicka Jan 19, 2024
47b2822
Remove GetPlateTypesAction
labkey-nicka Jan 19, 2024
54b2345
code review feedback
labkey-klum Jan 19, 2024
d6d8398
Merge branch 'develop' into fb_plate_type_schema
labkey-nicka Jan 19, 2024
ede887c
PlateId, Description
labkey-nicka Jan 19, 2024
16b5a4b
wells filled column
labkey-klum Jan 20, 2024
68bb0cd
Merge remote-tracking branch 'origin/fb_plate_type_schema' into fb_pl…
labkey-klum Jan 20, 2024
5b8b32a
cache plateType and plateSet in the plate instance
labkey-klum Jan 20, 2024
98867e7
Use ID
labkey-nicka Jan 20, 2024
489024d
Plate: serialize plate type
labkey-nicka Jan 23, 2024
6b35c1e
Merge branch 'develop' into fb_plate_type_schema
labkey-nicka Jan 23, 2024
9be2fe2
PlateImpl: return 0 when null _plateTypeObject
labkey-nicka Jan 23, 2024
e840ad3
Update script comment
labkey-nicka Jan 23, 2024
ab95725
modify upgrade script to not rely on DB deserialization on plate and …
labkey-klum Jan 23, 2024
807af26
make sure the plate name expression db sequences get created in the c…
labkey-klum Jan 24, 2024
263e5a4
Fix "AssayType" column reference
labkey-nicka Jan 24, 2024
cf8d6e3
Merge branch 'develop' into fb_plate_type_schema
labkey-nicka Jan 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion api/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
<url-pattern>*.post</url-pattern>
</filter-mapping>


<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,22 @@
import org.labkey.api.data.Container;
import org.labkey.api.query.ValidationException;
import org.labkey.api.security.User;
import org.labkey.api.util.Pair;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* User: klum
* Date: Jun 13, 2012
*/
public abstract class AbstractPlateTypeHandler implements PlateTypeHandler
public abstract class AbstractPlateLayoutHandler implements PlateLayoutHandler
{
Map<Pair<Integer, Integer>, PlateType> _plateTypeMap;

@Override
public void validateTemplate(Container container, User user, Plate template) throws ValidationException
{
Expand All @@ -40,6 +45,28 @@ public Map<String, List<String>> getDefaultGroupsForTypes()
return Collections.emptyMap();
}

abstract protected List<Pair<Integer, Integer>> getSupportedPlateSizes();

protected void validatePlateType(PlateType plateType)
{
if (!getSupportedPlateTypes().contains(plateType))
throw new IllegalStateException("The plate type : " + plateType.getDescription() + " is not supported for this layout handler.");
}

@Override
public List<PlateType> getSupportedPlateTypes()
{
if (_plateTypeMap == null)
{
_plateTypeMap = new HashMap<>();
for (PlateType type : PlateService.get().getPlateTypes())
{
_plateTypeMap.put(new Pair<>(type.getRows(), type.getColumns()), type);
}
}
return getSupportedPlateSizes().stream().filter(size -> _plateTypeMap.containsKey(size)).map(size -> _plateTypeMap.get(size)).collect(Collectors.toList());
}

@Override
public boolean showEditorWarningPanel()
{
Expand Down
4 changes: 3 additions & 1 deletion assay/api-src/org/labkey/api/assay/plate/Plate.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public interface Plate extends PropertySet, Identifiable

boolean isTemplate();

@NotNull PlateType getPlateTypeObject();

@Nullable PlateSet getPlateSetObject();

/**
Expand Down Expand Up @@ -76,7 +78,7 @@ public interface Plate extends PropertySet, Identifiable

int getWellGroupCount(WellGroup.Type type);

String getType();
String getAssayType();

@Override
@Nullable ActionURL detailsURL();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,33 @@

package org.labkey.api.assay.plate;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.labkey.api.data.Container;
import org.labkey.api.query.ValidationException;
import org.labkey.api.security.User;
import org.labkey.api.util.Pair;

import java.util.List;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
* User: jeckels
* Date: Apr 23, 2007
* Represents a handler that can create assay specific plate layouts
*/
public interface PlateTypeHandler
public interface PlateLayoutHandler
{
@NotNull
String getAssayType();

List<String> getTemplateTypes(Pair<Integer, Integer> size);
@NotNull List<String> getLayoutTypes(PlateType plateType);

/**
* createTemplate will be given a null value for templateTypeName when it is creating a new template which is a
* default for that assay type.
*/
Plate createTemplate(@Nullable String templateTypeName, Container container, int rowCount, int colCount) throws SQLException;
Plate createTemplate(@Nullable String templateTypeName, Container container, @NotNull PlateType plateType) throws SQLException;

List<Pair<Integer, Integer>> getSupportedPlateSizes();
List<PlateType> getSupportedPlateTypes();

List<WellGroup.Type> getWellGroupTypes();

Expand Down
23 changes: 16 additions & 7 deletions assay/api-src/org/labkey/api/assay/plate/PlateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,23 +88,21 @@ static PlateService get()
* Creates a new plate
* @param container The template's container.
* @param templateType The type of plate, if associated with a particular assay.
* @param rowCount The number of columns in the plate.
* @param columnCount The number of rows in the plate.
* @param plateType Specifies the overall shape of the plate
* @return A newly created plate instance
* @throws IllegalArgumentException Thrown if a template of the specified name already exists in the container.
*/
@NotNull Plate createPlate(Container container, String templateType, int rowCount, int columnCount);
@NotNull Plate createPlate(Container container, String templateType, @NotNull PlateType plateType);

/**
* Creates a new plate template.
* @param container The template's container.
* @param templateType The type of plate template, if associated with a particular assay.
* @param rowCount The number of columns in the plate.
* @param columnCount The number of rows in the plate.
* @param plateType Specifies the overall shape of the plate
* @return A newly created plate template instance.
* @throws IllegalArgumentException Thrown if a template of the specified name already exists in the container.
*/
@NotNull Plate createPlateTemplate(Container container, String templateType, int rowCount, int columnCount);
@NotNull Plate createPlateTemplate(Container container, String templateType, @NotNull PlateType plateType);

/**
* Adds a new well group to the plate
Expand Down Expand Up @@ -164,6 +162,17 @@ static PlateService get()
*/
@Nullable PlateSet getPlateSet(Container container, int plateSetId);

/**
* Returns the list of available plate types.
* @return
*/
@NotNull List<? extends PlateType> getPlateTypes();

/**
* Returns the plate type matching the specified shape.
*/
@Nullable PlateType getPlateType(int rows, int columns);

/**
* Returns the number of assay runs that are linked to the specified plate. Currently, this only works
* for the standard assay with plate support since other assays types do not store the plate ID with the
Expand Down Expand Up @@ -235,7 +244,7 @@ static PlateService get()
/**
* Registers a handler for a particular type of plate
*/
void registerPlateTypeHandler(PlateTypeHandler handler);
void registerPlateLayoutHandler(PlateLayoutHandler handler);

/**
* Calculates a dilution curve for the specified well groups.
Expand Down
2 changes: 2 additions & 0 deletions assay/api-src/org/labkey/api/assay/plate/PlateSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public interface PlateSet

String getName();

String getPlateSetId();

boolean isArchived();

List<Plate> getPlates(User user);
Expand Down
9 changes: 9 additions & 0 deletions assay/api-src/org/labkey/api/assay/plate/PlateType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.labkey.api.assay.plate;

public interface PlateType
{
Integer getRowId();
String getDescription();
Integer getRows();
Integer getColumns();
}
42 changes: 32 additions & 10 deletions assay/resources/schemas/assay.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
<column columnName="Name">
<description>The unique admin-provided name of each plate template (""NAb: 5 specimens in duplicate", for example).</description>
</column>
<column columnName="Description"/>
<column columnName="PlateId">
<columnTitle>Plate ID</columnTitle>
<isUserEditable>false</isUserEditable>
</column>
<column columnName="PlateSet">
<description>The Plate Set that this plate is assigned to.</description>
<fk>
Expand All @@ -37,6 +42,14 @@
<fkDbSchema>assay</fkDbSchema>
</fk>
</column>
<column columnName="PlateType">
<description>The plate type of this plate.</description>
<fk>
<fkColumnName>RowId</fkColumnName>
<fkTable>PlateType</fkTable>
<fkDbSchema>assay</fkDbSchema>
</fk>
</column>
<column columnName="CreatedBy">
<datatype>int</datatype>
<columnTitle>Created By</columnTitle>
Expand Down Expand Up @@ -79,20 +92,12 @@
<description>Boolean indicating whether each plate is a template versus an uploaded instance of a plate template.</description>
<shownInUpdateView>false</shownInUpdateView>
</column>
<column columnName="Rows">
<description>The number of rows in each plate.</description>
<shownInUpdateView>false</shownInUpdateView>
</column>
<column columnName="Columns">
<description>The number of columns in each plate.</description>
<shownInUpdateView>false</shownInUpdateView>
</column>
<column columnName="DataFileId">
<isUserEditable>false</isUserEditable>
<description>A unique text identifier (a GUID) for the data file associated with each plate.</description>
</column>
<column columnName="Type">
<description>A text label of the plate type ("NAb", for example).</description>
<column columnName="AssayType">
<description>A text label of the plate assay type ("NAb", for example).</description>
</column>
</columns>
</table>
Expand Down Expand Up @@ -178,6 +183,11 @@
<columns>
<column columnName="RowId"/>
<column columnName="Name"/>
<column columnName="Description"/>
<column columnName="PlateSetId">
<columnTitle>Plate Set ID</columnTitle>
<isUserEditable>false</isUserEditable>
</column>
<column columnName="Container"/>
<column columnName="CreatedBy"/>
<column columnName="Created"/>
Expand All @@ -186,4 +196,16 @@
<column columnName="Archived"/>
</columns>
</table>
<table tableName="PlateType" tableDbType="TABLE">
<description>Contains one row per plate type.</description>
<columns>
<column columnName="RowId">
<isHidden>true</isHidden>
</column>
<column columnName="Rows"/>
<column columnName="Columns"/>
<column columnName="Description"/>
<column columnName="Archived"/>
</columns>
</table>
</tables>
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
CREATE TABLE assay.PlateType
(
RowId SERIAL,
Rows INT NOT NULL,
Columns INT NOT NULL,
Description VARCHAR(300) NOT NULL,
Archived BOOLEAN NOT NULL DEFAULT FALSE,

CONSTRAINT PK_PlateType PRIMARY KEY (RowId),
CONSTRAINT UQ_PlateType_Rows_Cols UNIQUE (Rows, Columns)
);

INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (3, 4, '12 well (3x4)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (4, 6, '24 well (4x6)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (6, 8, '48 well (6x8)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (8, 12, '96 well (8x12)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (16, 24, '384 well (16x24)');
INSERT INTO assay.PlateType (Rows, Columns, Description, Archived) VALUES (32, 48, '1536 well (32x48)', TRUE);
INSERT INTO assay.PlateType (Rows, Columns, Description, Archived) VALUES (0, 0, 'Invalid Plate Type (Plates which were created with non-valid row & column combinations)', TRUE);

-- Rename type column to assayType
ALTER TABLE assay.Plate RENAME COLUMN Type TO AssayType;
-- Add plateType as a FK to assay.PlateType
ALTER TABLE assay.Plate ADD COLUMN PlateType INTEGER;
ALTER TABLE assay.Plate ADD CONSTRAINT FK_Plate_PlateType FOREIGN KEY (PlateType) REFERENCES assay.PlateType (RowId);

-- Add ID and description columns to Plate and PlateSet tables
ALTER TABLE assay.Plate ADD COLUMN PlateId VARCHAR(200);
ALTER TABLE assay.Plate ADD COLUMN Description VARCHAR(300);
ALTER TABLE assay.PlateSet ADD COLUMN PlateSetId VARCHAR(200);
ALTER TABLE assay.PlateSet ADD COLUMN Description VARCHAR(300);

-- Most existing plate sets will have a generated name, but mutated ones will get fixed up by the java upgrade script
UPDATE assay.PlateSet SET PlateSetId = Name;

UPDATE assay.Plate
SET PlateType =
CASE
WHEN (Rows = 3 AND Columns = 4) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 3 AND Columns = 4)
WHEN (Rows = 4 AND Columns = 6) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 4 AND Columns = 6)
WHEN (Rows = 6 AND Columns = 8) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 6 AND Columns = 8)
WHEN (Rows = 8 AND Columns = 12) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 8 AND Columns = 12)
WHEN (Rows = 16 AND Columns = 24) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 16 AND Columns = 24)
WHEN (Rows = 32 AND Columns = 48) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 32 AND Columns = 48)
ELSE (SELECT RowId FROM assay.PlateType WHERE Rows = 0 AND Columns = 0)
END
WHERE PlateType IS NULL;

ALTER TABLE assay.Plate ALTER COLUMN PlateType SET NOT NULL;
ALTER TABLE assay.Plate DROP COLUMN Rows;
ALTER TABLE assay.Plate DROP COLUMN Columns;

-- upgrade script to initialize plate and plateSet IDs
SELECT core.executeJavaUpgradeCode('initializePlateAndPlateSetIDs');

-- finalize plate and plateSet ID columns
ALTER TABLE assay.Plate ALTER COLUMN PlateId SET NOT NULL;
ALTER TABLE assay.Plate ADD CONSTRAINT UQ_Plate_PlateId UNIQUE (PlateId);

ALTER TABLE assay.PlateSet ALTER COLUMN PlateSetId SET NOT NULL;
ALTER TABLE assay.PlateSet ADD CONSTRAINT UQ_PlateSet_PlateSetId UNIQUE (PlateSetId);
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
CREATE TABLE assay.PlateType
(
RowId INT IDENTITY(1,1),
Rows INT NOT NULL,
Columns INT NOT NULL,
Description NVARCHAR(300) NOT NULL,
Archived BIT NOT NULL DEFAULT 0,

CONSTRAINT PK_PlateType PRIMARY KEY (RowId),
CONSTRAINT UQ_PlateType_Rows_Cols UNIQUE (Rows, Columns)
);

INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (3, 4, '12 well (3x4)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (4, 6, '24 well (4x6)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (6, 8, '48 well (6x8)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (8, 12, '96 well (8x12)');
INSERT INTO assay.PlateType (Rows, Columns, Description) VALUES (16, 24, '384 well (16x24)');
INSERT INTO assay.PlateType (Rows, Columns, Description, Archived) VALUES (32, 48, '1536 well (32x48)', 1);
INSERT INTO assay.PlateType (Rows, Columns, Description, Archived) VALUES (0, 0, 'Invalid Plate Type (Plates which were created with non-valid row & column combinations)', 1);

-- Rename type column to assayType
EXEC sp_rename 'assay.Plate.Type', 'AssayType', 'COLUMN';
-- Add type as a FK to assay.PlateType
ALTER TABLE assay.Plate ADD PlateType INT;
GO
ALTER TABLE assay.Plate ADD CONSTRAINT FK_Plate_PlateType FOREIGN KEY (PlateType) REFERENCES assay.PlateType (RowId);

-- Add ID and description columns to Plate and PlateSet tables
ALTER TABLE assay.Plate ADD PlateId NVARCHAR(200);
ALTER TABLE assay.Plate ADD Description NVARCHAR(300);
ALTER TABLE assay.PlateSet ADD PlateSetId NVARCHAR(200);
ALTER TABLE assay.PlateSet ADD Description NVARCHAR(300);
GO

-- Most existing plate sets will have a generated name, but mutated ones will get fixed up by the java upgrade script
UPDATE assay.PlateSet SET PlateSetId = Name;

UPDATE assay.Plate
SET PlateType =
CASE
WHEN (Rows = 3 AND Columns = 4) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 3 AND Columns = 4)
WHEN (Rows = 4 AND Columns = 6) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 4 AND Columns = 6)
WHEN (Rows = 6 AND Columns = 8) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 6 AND Columns = 8)
WHEN (Rows = 8 AND Columns = 12) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 8 AND Columns = 12)
WHEN (Rows = 16 AND Columns = 24) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 16 AND Columns = 24)
WHEN (Rows = 32 AND Columns = 48) THEN (SELECT RowId FROM assay.PlateType WHERE Rows = 32 AND Columns = 48)
ELSE (SELECT RowId FROM assay.PlateType WHERE Rows = 0 AND Columns = 0)
END
WHERE PlateType IS NULL;

ALTER TABLE assay.Plate ALTER COLUMN PlateType INT NOT NULL;
ALTER TABLE assay.Plate DROP COLUMN Rows;
ALTER TABLE assay.Plate DROP COLUMN Columns;

-- upgrade script to set the plate ID value in assay.Plate
EXEC core.executeJavaUpgradeCode 'initializePlateAndPlateSetIDs';

-- finalize plate and plateSet ID columns
ALTER TABLE assay.Plate ALTER COLUMN PlateId NVARCHAR(200) NOT NULL;
ALTER TABLE assay.Plate ADD CONSTRAINT UQ_Plate_PlateId UNIQUE (PlateId);

ALTER TABLE assay.PlateSet ALTER COLUMN PlateSetId NVARCHAR(200) NOT NULL;
ALTER TABLE assay.PlateSet ADD CONSTRAINT UQ_PlateSet_PlateSetId UNIQUE (PlateSetId);
Loading