Skip to content

Commit

Permalink
Support assay import of cross folder plates
Browse files Browse the repository at this point in the history
  • Loading branch information
labkey-klum committed Sep 27, 2023
1 parent d71e6bc commit 4e2b693
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 32 deletions.
4 changes: 2 additions & 2 deletions assay/api-src/org/labkey/api/assay/plate/PlateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ static PlateService get()
* for the standard assay with plate support since other assays types do not store the plate ID with the
* run.
*/
int getRunCountUsingPlate(@NotNull Container c, @NotNull Plate plate);
int getRunCountUsingPlate(@NotNull Container c, @NotNull User user, @NotNull Plate plate);

List<? extends ExpRun> getRunsUsingPlate(@NotNull Container c, @NotNull Plate plate);
List<? extends ExpRun> getRunsUsingPlate(@NotNull Container c, @NotNull User user, @NotNull Plate plate);

/**
* Creates a new plate template.
Expand Down
4 changes: 2 additions & 2 deletions assay/src/org/labkey/assay/PlateController.java
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ public void validateForm(DataViewSnapshotSelectionForm form, Errors errors)
@Override
public Object execute(DataViewSnapshotSelectionForm form, BindException errors) throws Exception
{
var results = PlateManager.get().getPlateOperationConfirmationData(getContainer(), form.getIds(false));
var results = PlateManager.get().getPlateOperationConfirmationData(getContainer(), getUser(), form.getIds(false));
return success(results);
}
}
Expand Down Expand Up @@ -849,7 +849,7 @@ public Object execute(GetPlateForm form, BindException errors) throws Exception
Plate plate = PlateManager.get().getPlate(cf, form.getRowId());

if (plate != null && Boolean.TRUE.equals(form.getIncludeRunCount()))
((PlateImpl) plate).setRunCount(PlateManager.get().getRunCountUsingPlate(plate.getContainer(), plate));
((PlateImpl) plate).setRunCount(PlateManager.get().getRunCountUsingPlate(plate.getContainer(), getUser(), plate));

return plate;
}
Expand Down
2 changes: 1 addition & 1 deletion assay/src/org/labkey/assay/TsvAssayProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ public void changeDomain(User user, ExpProtocol protocol, GWTDomain<GWTPropertyD
Optional<GWTPropertyDescriptor> plateTemplateColumn = update.getFields().stream().filter(field -> field.getName().equals(AssayPlateMetadataService.PLATE_TEMPLATE_COLUMN_NAME)).findFirst();
if (plateTemplateColumn.isPresent())
{
// Ensure the lookup container is null so it defaults to "Current Folder" to more easily support
// Ensure the lookup container is null, so it defaults to "Current Folder" to more easily support
// cross-folder support.
GWTPropertyDescriptor plateTemplate = plateTemplateColumn.get();
plateTemplate.setLookupContainer(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public void addAssayPlateMetadata(
if (property != null)
plateLsid = Lsid.parse(String.valueOf(run.getProperty(property)));

Map<Position, Map<String, Object>> plateData = prepareMergedPlateData(plateLsid, plateMetadata, user, protocol, true);
Map<Position, Map<String, Object>> plateData = prepareMergedPlateData(container, user, plateLsid, plateMetadata, protocol, true);
Domain domain = getPlateDataDomain(protocol);

Map<String, PropertyDescriptor> descriptorMap = new CaseInsensitiveHashMap<>();
Expand Down Expand Up @@ -158,17 +158,18 @@ public void addAssayPlateMetadata(
* to metadata properties.
*/
private Map<Position, Map<String, Object>> prepareMergedPlateData(
Container container,
User user,
Lsid plateLsid,
Map<String, MetadataLayer> plateMetadata,
@Nullable User user,
ExpProtocol protocol,
boolean ensurePlateDomain // true to create the plate domain and properties if they don't exist
) throws ExperimentException
{
_domainDirty = false;
_propValues.clear();

Plate plate = PlateService.get().getPlate(protocol.getContainer(), plateLsid);
Plate plate = PlateService.get().getPlate(PlateManager.get().getPlateContainerFilter(protocol, container, user), plateLsid);
if (plate == null)
throw new ExperimentException("Unable to resolve the plate template for the run");

Expand Down Expand Up @@ -272,7 +273,7 @@ public List<Map<String, Object>> mergePlateMetadata(

if (plateMetadata != null)
{
Map<Position, Map<String, Object>> plateData = prepareMergedPlateData(plateLsid, plateMetadata, null, protocol, false);
Map<Position, Map<String, Object>> plateData = prepareMergedPlateData(container, user, plateLsid, plateMetadata, protocol, false);
for (Map<String, Object> row : mergedRows)
{
PositionImpl well = new PositionImpl(null, String.valueOf(row.get(AssayResultDomainKind.WELL_LOCATION_COLUMN_NAME)));
Expand All @@ -287,12 +288,12 @@ public List<Map<String, Object>> mergePlateMetadata(
if (AssayPlateMetadataService.isExperimentalAppPlateEnabled())
{
// include metadata that may have been applied directly to the plate
Plate plate = PlateService.get().getPlate(protocol.getContainer(), plateLsid);
Plate plate = PlateService.get().getPlate(PlateManager.get().getPlateContainerFilter(protocol, container, user), plateLsid);
if (plate == null)
throw new ExperimentException("Unable to resolve the plate for the run");

// if there are metadata fields configured for this plate
if (!PlateManager.get().getFields(container, plate.getRowId()).isEmpty())
if (!plate.getCustomFields().isEmpty())
{
// create the map of well locations to the well
Map<Position, Well> positionToWell = new HashMap<>();
Expand All @@ -310,7 +311,7 @@ public List<Map<String, Object>> mergePlateMetadata(

if (positionToWell.containsKey(well))
{
for (WellCustomField customField : PlateManager.get().getWellCustomFields(container, user, plate.getRowId(), positionToWell.get(well).getRowId()))
for (WellCustomField customField : PlateManager.get().getWellCustomFields(user, plate, positionToWell.get(well).getRowId()))
{
row.put(customField.getName(), customField.getValue());
}
Expand Down Expand Up @@ -493,7 +494,7 @@ public OntologyManager.UpdateableTableImportHelper getImportHelper(
if (property != null)
plateLsid = Lsid.parse(String.valueOf(run.getProperty(property)));

Plate plate = PlateService.get().getPlate(protocol.getContainer(), plateLsid);
Plate plate = PlateService.get().getPlate(PlateManager.get().getPlateContainerFilter(protocol, container, user), plateLsid);
if (plate == null)
throw new ExperimentException(String.format("Unable to resolve the plate : %s for the run", plateLsid));

Expand Down
38 changes: 23 additions & 15 deletions assay/src/org/labkey/assay/plate/PlateManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,9 @@ public List<Plate> getPlateTemplates(Container container)
}

@Override
public List<? extends ExpRun> getRunsUsingPlate(@NotNull Container c, @NotNull Plate plate)
public List<? extends ExpRun> getRunsUsingPlate(@NotNull Container c, @NotNull User user, @NotNull Plate plate)
{
SqlSelector se = selectRunUsingPlate(c, plate);
SqlSelector se = selectRunUsingPlate(c, user, plate);
if (se == null)
return emptyList();

Expand All @@ -331,20 +331,17 @@ public List<? extends ExpRun> getRunsUsingPlate(@NotNull Container c, @NotNull P
}

@Override
public int getRunCountUsingPlate(@NotNull Container c, @NotNull Plate plate)
public int getRunCountUsingPlate(@NotNull Container c, @NotNull User user, @NotNull Plate plate)
{
SqlSelector se = selectRunUsingPlate(c, plate);
SqlSelector se = selectRunUsingPlate(c, user, plate);
if (se == null)
return 0;

return (int) se.getRowCount();
}

private @Nullable SqlSelector selectRunUsingPlate(@NotNull Container c, @NotNull Plate plate)
private @Nullable SqlSelector selectRunUsingPlate(@NotNull Container c, @NotNull User user, @NotNull Plate plate)
{
if (plate == null)
return null;

// first, get the list of GPAT protocols in the container
AssayProvider gpat = AssayService.get().getProvider(TsvAssayProvider.NAME);
if (gpat == null)
Expand All @@ -369,12 +366,14 @@ public int getRunCountUsingPlate(@NotNull Container c, @NotNull Plate plate)
List<Integer> plateTemplatePropIds = plateTemplateProps.stream().map(PropertyDescriptor::getPropertyId).toList();

// query for runs with that property that point to the plate by LSID
ContainerFilter cf = getPlateContainerFilter(null, c, user);
SQLFragment sql = new SQLFragment()
.append("SELECT r.rowId\n")
.append("FROM ").append(ExperimentService.get().getTinfoExperimentRun(), "r").append("\n")
.append("INNER JOIN ").append(OntologyManager.getTinfoObject(), "o").append(" ON o.objectUri = r.lsid\n")
.append("INNER JOIN ").append(OntologyManager.getTinfoObjectProperty(), "op").append(" ON op.objectId = o.objectId\n")
.append("WHERE r.container = ?\n").add(c.getId())
.append("WHERE ")
.append(cf.getSQLFragment(AssayDbSchema.getInstance().getSchema(), new SQLFragment("r.container"))).append("\n")
.append("AND op.propertyId ").appendInClause(plateTemplatePropIds, AssayDbSchema.getInstance().getSchema().getSqlDialect()).append("\n")
.append("AND op.stringvalue = ?").add(plate.getLSID());

Expand Down Expand Up @@ -416,6 +415,16 @@ public Plate createPlateTemplate(Container container, String templateType, int r
return PlateCache.getPlate(cf, lsid);
}

/**
* Helper to create container filters to support assay import using cross folder
* plates
*/
public ContainerFilter getPlateContainerFilter(@Nullable ExpProtocol protocol, Container container, User user)
{
ContainerFilter defaultCf = ContainerFilter.Type.Current.create(protocol != null ? protocol.getContainer() : container, user);
return QueryService.get().getProductContainerFilterForLookups(container, user, defaultCf);
}

@Override
public @Nullable Plate getPlate(Container container, Lsid lsid)
{
Expand Down Expand Up @@ -1234,6 +1243,7 @@ public PlateType getPlateType(@NotNull Plate plate)

public @NotNull Map<String, List<Map<String, Integer>>> getPlateOperationConfirmationData(
@NotNull Container container,
@NotNull User user,
@NotNull Set<Integer> plateRowIds
)
{
Expand All @@ -1247,7 +1257,7 @@ public PlateType getPlateType(@NotNull Plate plate)
// TODO: This is really expensive. Find a way to consolidate this check into a single query.
permittedIds.forEach(plateRowId -> {
Plate plate = getPlate(container, plateRowId);
if (plate == null || getRunCountUsingPlate(container, plate) > 0)
if (plate == null || getRunCountUsingPlate(container, user, plate) > 0)
notPermittedIds.add(plateRowId);
});
permittedIds.removeAll(notPermittedIds);
Expand Down Expand Up @@ -1510,18 +1520,16 @@ private List<DomainProperty> _getFields(Container container, User user, Integer
return fields;
}

public List<WellCustomField> getWellCustomFields(Container container, User user, Integer plateId, Integer wellId)
public List<WellCustomField> getWellCustomFields(User user, Plate plate, Integer wellId)
{
Plate plate = requirePlate(container, plateId, "Failed to get well custom fields.");

Well well = plate.getWell(wellId);
if (well == null)
throw new IllegalArgumentException("Failed to get well custom fields. Well id \"" + wellId + "\" not found.");

List<WellCustomField> fields = _getFields(container, user, plateId).stream().map(WellCustomField::new).toList();
List<WellCustomField> fields = _getFields(plate.getContainer(), user, plate.getRowId()).stream().map(WellCustomField::new).toList();

// need to get the well values associated with each custom field
Map<String, Object> properties = OntologyManager.getProperties(container, well.getLsid());
Map<String, Object> properties = OntologyManager.getProperties(plate.getContainer(), well.getLsid());
for (WellCustomField field : fields)
field.setValue(properties.get(field.getPropertyURI()));

Expand Down
4 changes: 2 additions & 2 deletions assay/src/org/labkey/assay/plate/query/PlateTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ protected Map<String, Object> updateRow(User user, Container container, Map<Stri
if (plate == null)
return Collections.emptyMap();

int runsInUse = PlateManager.get().getRunCountUsingPlate(container, plate);
int runsInUse = PlateManager.get().getRunCountUsingPlate(container, user, plate);
if (runsInUse > 0)
throw new QueryUpdateServiceException(String.format("%s is used by %d runs and cannot be updated", plate.isTemplate() ? "Plate template" : "Plate", runsInUse));

Expand All @@ -254,7 +254,7 @@ protected Map<String, Object> deleteRow(User user, Container container, Map<Stri
if (plate == null)
return Collections.emptyMap();

int runsInUse = PlateManager.get().getRunCountUsingPlate(container, plate);
int runsInUse = PlateManager.get().getRunCountUsingPlate(container, user, plate);
if (runsInUse > 0)
throw new QueryUpdateServiceException(String.format("%s is used by %d runs and cannot be deleted", plate.isTemplate() ? "Plate template" : "Plate", runsInUse));

Expand Down
2 changes: 1 addition & 1 deletion assay/src/org/labkey/assay/plate/query/WellTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ protected Map<String, Object> updateRow(User user, Container container, Map<Stri
Plate plate = PlateManager.get().getPlate(container, (Integer)oldRow.get("plateId"));
if (plate != null)
{
int runsInUse = PlateManager.get().getRunCountUsingPlate(container, plate);
int runsInUse = PlateManager.get().getRunCountUsingPlate(container, user, plate);
if (runsInUse > 0)
throw new QueryUpdateServiceException(String.format("This %s is used by %d runs and its wells cannot be modified.", plate.isTemplate() ? "Plate template" : "Plate", runsInUse));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
Map<Plate, Integer> plateTemplateRunCount = new HashMap<>();
for (Plate template : plateTemplates)
{
int count = PlateService.get().getRunCountUsingPlate(c, template);
int count = PlateService.get().getRunCountUsingPlate(c, getUser(), template);
plateTemplateRunCount.put(template, count);
}
%>
Expand Down

0 comments on commit 4e2b693

Please sign in to comment.