diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/ISampleListingQuery.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/ISampleListingQuery.java index 3db8e1e751a7ad32c737410e17be91901dbf7d95..30a0d043196334c5e3b649a3d85c68525314b235 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/ISampleListingQuery.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/ISampleListingQuery.java @@ -41,9 +41,13 @@ public interface ISampleListingQuery extends BaseQuery + "s.registration_timestamp as s_registration_timestamp, " + "s.modification_timestamp as s_modification_timestamp, sp.code as sp_code, " + "st.id as st_id, st.code as st_code, pe.first_name as pe_first_name, " - + "pe.last_name as pe_last_name, pe.user_id as pe_user_id, pe.email as pe_email " + + "pe.last_name as pe_last_name, pe.user_id as pe_user_id, pe.email as pe_email, " + + "e.code as exp_code, p.code as proj_code, ps.code as proj_space_code " + "from samples as s join sample_types as st on s.saty_id = st.id " + "left join spaces as sp on s.space_id = sp.id " + + "left join experiments as e on s.expe_id = e.id " + + "left join projects as p on e.proj_id = p.id " + + "left join spaces as ps on p.space_id = ps.id " + "join persons as pe on s.pers_id_registerer = pe.id where s.id = any(?{1}) ", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE) public List<SampleRecord> listSamplesByIds(LongSet sampleIDs); @@ -67,7 +71,7 @@ public interface ISampleListingQuery extends BaseQuery public List<SampleRelationshipRecord> getDescendants(Long relationshipID, LongSet sampleIDs); @Select(sql = "with recursive connected_relationships as (select * from sample_relationships " - + "where relationship_id = ?{1} and sample_id_parent = any(?{2}) " + + "where relationship_id = ?{1} and sample_id_child = any(?{2}) " + "union select sr.* from connected_relationships as cr " + "join sample_relationships as sr on cr.sample_id_parent = sr.sample_id_child) " + "select * from connected_relationships", parameterBindings = diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleLister.java index 8389c544ac29e190cbf762b42527051a43bd66a9..53e28f8c2db5735cce07e4ed3ed95f334945609c 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleLister.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleLister.java @@ -108,9 +108,11 @@ public class SampleLister implements ISampleLister { descendants = query.getChildren(getRelationShipType(), rootSampleIdSet); } + LongSet descendentIdSet = new LongOpenHashSet(); for (SampleRelationshipRecord relationShip : descendants) { sampleIdSet.add(relationShip.sample_id_child); + descendentIdSet.add(relationShip.sample_id_child); } List<SampleRelationshipRecord> ancestors = Collections.emptyList(); if (fetchOptions.contains(SampleFetchOption.ANCESTORS)) @@ -120,34 +122,72 @@ public class SampleLister implements ISampleLister { ancestors = query.getParents(getRelationShipType(), rootSampleIdSet); } + LongSet ancestorIdSet = new LongOpenHashSet(); for (SampleRelationshipRecord relationShip : ancestors) { sampleIdSet.add(relationShip.sample_id_parent); + ancestorIdSet.add(relationShip.sample_id_parent); } - List<SampleRecord> list = query.listSamplesByIds(sampleIdSet); TableMap<Long, SampleRecord> sampleRecords = - new TableMap<Long, SampleRecord>(list, ID_EXTRACTOR); + getAllSamples(sampleIdSet, rootSampleIdSet, descendentIdSet, ancestorIdSet, + fetchOptions); if (fetchOptions.contains(SampleFetchOption.PROPERTIES)) { enrichWithProperties(sampleRecords, sampleIdSet); } - enrichWithDescendants(descendants, sampleRecords); - enrichWithAncestors(ancestors, sampleRecords); + enrichWithDescendants(descendants, sampleRecords, + fetchOptions.contains(SampleFetchOption.DESCENDANTS)); + enrichWithAncestors(ancestors, sampleRecords, + fetchOptions.contains(SampleFetchOption.ANCESTORS)); List<Sample> samples = new ArrayList<Sample>(); for (Long rootSampleID : sampleIDs) { SampleRecord sampleRecord = sampleRecords.tryGet(rootSampleID); if (sampleRecord != null) { - samples.add(createSample(sampleRecord, fetchOptions)); + samples.add(createSample(sampleRecord)); } } Collections.sort(samples, SAMPLE_COMPARATOR); return samples; } + public TableMap<Long, SampleRecord> getAllSamples(LongSet sampleIdSet, LongSet rootSampleIdSet, + LongSet descendentIdSet, LongSet ancestorIdSet, EnumSet<SampleFetchOption> fetchOptions) + { + List<SampleRecord> list = query.listSamplesByIds(sampleIdSet); + TableMap<Long, SampleRecord> sampleRecords = + new TableMap<Long, SampleRecord>(list, ID_EXTRACTOR); + for (SampleRecord sampleRecord : sampleRecords) + { + sampleRecord.fetchOptions = createAppropriateFetchOptions(fetchOptions); + if (rootSampleIdSet.contains(sampleRecord.s_id)) + { + if (fetchOptions.contains(SampleFetchOption.CHILDREN) + || fetchOptions.contains(SampleFetchOption.DESCENDANTS)) + { + sampleRecord.fetchOptions.add(SampleFetchOption.CHILDREN); + } + if (fetchOptions.contains(SampleFetchOption.PARENTS) + || fetchOptions.contains(SampleFetchOption.ANCESTORS)) + { + sampleRecord.fetchOptions.add(SampleFetchOption.PARENTS); + } + } else if (fetchOptions.contains(SampleFetchOption.ANCESTORS) + && ancestorIdSet.contains(sampleRecord.s_id)) + { + sampleRecord.fetchOptions.add(SampleFetchOption.PARENTS); + } else if (fetchOptions.contains(SampleFetchOption.DESCENDANTS) + && descendentIdSet.contains(sampleRecord.s_id)) + { + sampleRecord.fetchOptions.add(SampleFetchOption.CHILDREN); + } + } + return sampleRecords; + } + public void enrichWithAncestors(List<SampleRelationshipRecord> ancestors, - TableMap<Long, SampleRecord> sampleRecords) + TableMap<Long, SampleRecord> sampleRecords, boolean allAncestors) { for (SampleRelationshipRecord ancestor : ancestors) { @@ -158,6 +198,10 @@ public class SampleLister implements ISampleLister if (child.parents == null) { child.parents = new LinkedList<SampleRecord>(); + if (allAncestors) + { + child.fetchOptions.add(SampleFetchOption.PARENTS); + } } child.parents.add(parent); } @@ -165,7 +209,7 @@ public class SampleLister implements ISampleLister } public void enrichWithDescendants(List<SampleRelationshipRecord> descendants, - TableMap<Long, SampleRecord> sampleRecords) + TableMap<Long, SampleRecord> sampleRecords, boolean allDescendants) { for (SampleRelationshipRecord descendant : descendants) { @@ -176,15 +220,20 @@ public class SampleLister implements ISampleLister if (parent.children == null) { parent.children = new LinkedList<SampleRecord>(); + if (allDescendants) + { + parent.fetchOptions.add(SampleFetchOption.CHILDREN); + } } parent.children.add(child); } } } - private void enrichWithProperties(TableMap<Long, SampleRecord> sampleRecords, LongSet sampleIDs) + private void enrichWithProperties(TableMap<Long, SampleRecord> sampleRecords, + LongSet sampleIdSet) { - List<PropertyRecord> properties = query.getProperties(sampleIDs); + List<PropertyRecord> properties = query.getProperties(sampleIdSet); for (PropertyRecord propertyRecord : properties) { SampleRecord sampleRecord = sampleRecords.tryGet(propertyRecord.entity_id); @@ -199,7 +248,7 @@ public class SampleLister implements ISampleLister } } - private Sample createSample(SampleRecord sampleRecord, EnumSet<SampleFetchOption> fetchOptions) + private Sample createSample(SampleRecord sampleRecord) { Sample.SampleInitializer initializer = new Sample.SampleInitializer(); initializer.setId(sampleRecord.s_id); @@ -221,6 +270,11 @@ public class SampleLister implements ISampleLister initializer.setRegistrationDetails(new EntityRegistrationDetails(detailsInitializer)); initializer.setSampleTypeId(sampleRecord.st_id); initializer.setSampleTypeCode(sampleRecord.st_code); + if (sampleRecord.exp_code != null) + { + initializer.setExperimentIdentifierOrNull("/" + sampleRecord.proj_space_code + "/" + + sampleRecord.proj_code + "/" + sampleRecord.exp_code); + } Map<String, String> properties = sampleRecord.properties; if (properties != null) { @@ -229,36 +283,14 @@ public class SampleLister implements ISampleLister initializer.putProperty(entry.getKey(), entry.getValue()); } } - EnumSet<SampleFetchOption> rootFetchOptions = createAppropriateFetchOptions(fetchOptions); - if (fetchOptions.contains(SampleFetchOption.CHILDREN) - || fetchOptions.contains(SampleFetchOption.DESCENDANTS)) - { - rootFetchOptions.add(SampleFetchOption.CHILDREN); - } - if (fetchOptions.contains(SampleFetchOption.PARENTS) - || fetchOptions.contains(SampleFetchOption.ANCESTORS)) - { - rootFetchOptions.add(SampleFetchOption.PARENTS); - } - initializer.setRetrievedFetchOptions(rootFetchOptions); + initializer.setRetrievedFetchOptions(sampleRecord.fetchOptions); if (sampleRecord.children != null) { - EnumSet<SampleFetchOption> childrenOptions = - createAppropriateFetchOptions(fetchOptions); - if (fetchOptions.contains(SampleFetchOption.DESCENDANTS)) - { - childrenOptions.add(SampleFetchOption.CHILDREN); - } - initializer.setChildren(createChildren(sampleRecord.children, childrenOptions)); + initializer.setChildren(createChildren(sampleRecord.children)); } if (sampleRecord.parents != null) { - EnumSet<SampleFetchOption> parentsOptions = createAppropriateFetchOptions(fetchOptions); - if (fetchOptions.contains(SampleFetchOption.ANCESTORS)) - { - parentsOptions.add(SampleFetchOption.PARENTS); - } - initializer.setParents(createParents(sampleRecord.parents, parentsOptions)); + initializer.setParents(createParents(sampleRecord.parents)); } return new Sample(initializer); } @@ -271,25 +303,23 @@ public class SampleLister implements ISampleLister : SampleFetchOption.BASIC); } - private List<Sample> createChildren(List<SampleRecord> childRecords, - EnumSet<SampleFetchOption> fetchOptions) + private List<Sample> createChildren(List<SampleRecord> childRecords) { List<Sample> children = new ArrayList<Sample>(); for (SampleRecord childRecord : childRecords) { - children.add(createSample(childRecord, fetchOptions)); + children.add(createSample(childRecord)); } Collections.sort(children, SAMPLE_COMPARATOR); return children; } - private List<Sample> createParents(List<SampleRecord> parentRecords, - EnumSet<SampleFetchOption> fetchOptions) + private List<Sample> createParents(List<SampleRecord> parentRecords) { List<Sample> parents = new ArrayList<Sample>(); for (SampleRecord parentRecord : parentRecords) { - parents.add(createSample(parentRecord, fetchOptions)); + parents.add(createSample(parentRecord)); } Collections.sort(parents, SAMPLE_COMPARATOR); return parents; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleRecord.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleRecord.java index c66cec766fcd28ef2b80cea4500ee047e69e5450..717e4a743b0432f0776165e3521272addbb53b22 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleRecord.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/samplelister/SampleRecord.java @@ -17,9 +17,12 @@ package ch.systemsx.cisd.openbis.generic.server.business.bo.fetchoptions.samplelister; import java.util.Date; +import java.util.EnumSet; import java.util.List; import java.util.Map; +import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SampleFetchOption; + /** * @author Franz-Josef Elmer */ @@ -50,10 +53,18 @@ public class SampleRecord public String pe_email; + public String exp_code; + + public String proj_code; + + public String proj_space_code; + public List<SampleRecord> children; public List<SampleRecord> parents; public Map<String, String> properties; + public EnumSet<SampleFetchOption> fetchOptions; + } diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java index 449004d45b1dea2d98ba6c6aaec32a2b5c70de8f..91b3e8dfbbd95157ca8e2ed9c4ac0d3e9088435f 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java @@ -191,6 +191,149 @@ public class GeneralInformationServiceTest extends SystemTestCase assertEntities("[]", samples); } + @Test + public void testSearchForSamplesWithParents() + { + SearchCriteria searchCriteria = new SearchCriteria(); + searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.TYPE, + "DILUTION_PLATE")); + + EnumSet<SampleFetchOption> fetchOptions = + EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.PARENTS); + List<Sample> samples = + generalInformationService.searchForSamples(sessionToken, searchCriteria, + fetchOptions); + + assertEntities("[/CISD/3V-125, /CISD/3V-126, /CISD/DP1-A, /CISD/DP1-B, /CISD/DP2-A, /DP]", + samples); + assertEquals(fetchOptions, samples.get(0).getRetrievedFetchOptions()); + List<Sample> parents = samples.get(0).getParents(); + assertEntities("[/CISD/MP002-1]", parents); + assertEquals("MP002-1", parents.get(0).getCode()); + assertEquals(EnumSet.of(SampleFetchOption.PROPERTIES), parents.get(0) + .getRetrievedFetchOptions()); + assertEquals("{PLATE_GEOMETRY=384_WELLS_16X24}", parents.get(0).getProperties().toString()); + } + + @Test + public void testSearchForSamplesWithParentsButNoProperties() + { + SearchCriteria searchCriteria = new SearchCriteria(); + searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.TYPE, + "DILUTION_PLATE")); + + EnumSet<SampleFetchOption> fetchOptions = EnumSet.of(SampleFetchOption.PARENTS); + List<Sample> samples = + generalInformationService.searchForSamples(sessionToken, searchCriteria, + fetchOptions); + + assertEntities("[/CISD/3V-125, /CISD/3V-126, /CISD/DP1-A, /CISD/DP1-B, /CISD/DP2-A, /DP]", + samples); + assertEquals(EnumSet.of(SampleFetchOption.BASIC, SampleFetchOption.PARENTS), samples.get(0) + .getRetrievedFetchOptions()); + assertEquals(null, samples.get(0).getExperimentIdentifierOrNull()); + assertEquals("{}", samples.get(0).getProperties().toString()); + List<Sample> parents = samples.get(0).getParents(); + assertEntities("[/CISD/MP002-1]", parents); + assertEquals("MP002-1", parents.get(0).getCode()); + assertEquals(EnumSet.of(SampleFetchOption.BASIC), parents.get(0).getRetrievedFetchOptions()); + assertEquals("{}", parents.get(0).getProperties().toString()); + } + + @Test + public void testSearchForSamplesWithParentsAndDescendentsButNoProperties() + { + SearchCriteria searchCriteria = new SearchCriteria(); + searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.TYPE, + "DILUTION_PLATE")); + + EnumSet<SampleFetchOption> fetchOptions = + EnumSet.of(SampleFetchOption.PARENTS, SampleFetchOption.DESCENDANTS); + List<Sample> samples = + generalInformationService.searchForSamples(sessionToken, searchCriteria, + fetchOptions); + + assertEntities("[/CISD/3V-125, /CISD/3V-126, /CISD/DP1-A, /CISD/DP1-B, /CISD/DP2-A, /DP]", + samples); + assertEquals(EnumSet.of(SampleFetchOption.BASIC, SampleFetchOption.PARENTS, + SampleFetchOption.CHILDREN), samples.get(0).getRetrievedFetchOptions()); + assertEquals(null, samples.get(0).getExperimentIdentifierOrNull()); + assertEquals("{}", samples.get(0).getProperties().toString()); + List<Sample> parents = samples.get(0).getParents(); + assertEntities("[/CISD/MP002-1]", parents); + assertEquals("MP002-1", parents.get(0).getCode()); + assertEquals(EnumSet.of(SampleFetchOption.BASIC), parents.get(0).getRetrievedFetchOptions()); + assertEquals("{}", parents.get(0).getProperties().toString()); + List<Sample> children = samples.get(0).getChildren(); + assertEntities("[/CISD/3VCP5, /CISD/3VCP6, /CISD/3VCP7, /CISD/3VCP8]", children); + assertEquals("3VCP5", children.get(0).getCode()); + assertEquals(EnumSet.of(SampleFetchOption.BASIC, SampleFetchOption.CHILDREN), + children.get(0).getRetrievedFetchOptions()); + assertEquals("{}", children.get(0).getProperties().toString()); + assertEntities("[]", children.get(0).getChildren()); + } + + @Test + public void testSearchForSamplesWithAncestors() + { + SearchCriteria searchCriteria = new SearchCriteria(); + searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, + "3VCP*")); + + EnumSet<SampleFetchOption> fetchOptions = + EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.ANCESTORS); + List<Sample> samples = + generalInformationService.searchForSamples(sessionToken, searchCriteria, + fetchOptions); + + assertEntities("[/CISD/3VCP5, /CISD/3VCP6, /CISD/3VCP7, /CISD/3VCP8]", samples); + assertEquals(EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.PARENTS), samples + .get(0).getRetrievedFetchOptions()); + assertEquals("/CISD/NEMO/EXP10", samples.get(0).getExperimentIdentifierOrNull()); + List<Sample> parents = samples.get(0).getParents(); + assertEntities("[/CISD/3V-125]", parents); + assertEquals("3V-125", parents.get(0).getCode()); + assertEquals(EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.PARENTS), parents + .get(0).getRetrievedFetchOptions()); + List<Sample> grandParents = parents.get(0).getParents(); + assertEntities("[/CISD/MP002-1]", grandParents); + assertEquals("MP002-1", grandParents.get(0).getCode()); + assertEquals(EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.PARENTS), + grandParents.get(0).getRetrievedFetchOptions()); + assertEquals("{PLATE_GEOMETRY=384_WELLS_16X24}", grandParents.get(0).getProperties() + .toString()); + assertEntities("[]", grandParents.get(0).getParents()); + } + + @Test + public void testSearchForSamplesWithDescendants() + { + SearchCriteria searchCriteria = new SearchCriteria(); + searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, + "MP002-1 ")); + + EnumSet<SampleFetchOption> fetchOptions = + EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.DESCENDANTS); + List<Sample> samples = + generalInformationService.searchForSamples(sessionToken, searchCriteria, + fetchOptions); + + assertEntities("[/CISD/MP002-1]", samples); + assertEquals(EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.CHILDREN), samples + .get(0).getRetrievedFetchOptions()); + List<Sample> children = samples.get(0).getChildren(); + assertEntities("[/CISD/3V-125, /CISD/3V-126]", children); + assertEquals(EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.CHILDREN), children + .get(0).getRetrievedFetchOptions()); + List<Sample> grandChildren = children.get(0).getChildren(); + assertEntities("[/CISD/3VCP5, /CISD/3VCP6, /CISD/3VCP7, /CISD/3VCP8]", grandChildren); + assertEquals("3VCP5", grandChildren.get(0).getCode()); + assertEquals(EnumSet.of(SampleFetchOption.PROPERTIES, SampleFetchOption.CHILDREN), + grandChildren.get(0).getRetrievedFetchOptions()); + assertEquals("{}", grandChildren.get(0).getProperties().toString()); + assertEntities("[]", grandChildren.get(0).getChildren()); + } + @Test public void testListSamplesForExperiment() {