source: trunk/src/groovy/dbnp/query/SampleSearch.groovy @ 1424

Last change on this file since 1424 was 1424, checked in by robert@…, 10 years ago

Improved querying and created a possibility to search for assays

File size: 6.2 KB
Line 
1/**
2 * SampleSearch Domain Class
3 *
4 * This class provides querying capabilities for searching for samples
5 *
6 * @author  Robert Horlings (robert@isdat.nl)
7 * @since       20110118
8 * @package     dbnp.query
9 *
10 * Revision information:
11 * $Rev$
12 * $Author$
13 * $Date$
14 */
15package dbnp.query
16
17import java.util.List;
18import dbnp.studycapturing.*;
19
20class SampleSearch extends Search {
21        public SampleSearch() {
22                this.entity = "Sample";
23        }
24
25        /**
26         * Searches for samples based on the given criteria. All criteria have to be satisfied and
27         * criteria for the different entities are satisfied as follows:
28         *
29         *              Sample.title = 'abc'           
30         *                              Only samples are returned from studies with title 'abc'
31         *             
32         *              Subject.species = 'human'
33         *                              Only samples are returned from subjects with species = 'human' 
34         *
35         *              Sample.name = 'sample 1'
36         *                              Only samples are returned with name = 'sample 1'
37         *
38         *              Event.startTime = '0s'
39         *                              Only samples are returned from subjects that have had an event with start time = '0s' 
40         *
41         *              SamplingEvent.startTime = '0s'
42         *                              Only samples are returned that have originated from a sampling event with start time = '0s' 
43         *
44         *              Assay.module = 'metagenomics'
45         *                              Only samples are returned that have been processed in an assay with module = metagenomics 
46         *
47         * When searching for more than one criterion per entity, these are taken combined. Searching for
48         *
49         *              Subject.species = 'human'
50         *              Subject.name = 'Jan'
51         *
52         *  will result in all samples from a human subject named 'Jan'. Samples from a mouse subject
53         *  named 'Jan' or a human subject named 'Kees' won't satisfy the criteria.
54         *     
55         */
56        @Override
57        void execute() {
58                // TODO: check for authorization for these studies?
59
60                // If no criteria are found, return all samples
61                if( !criteria || criteria.size() == 0 ) {
62                        results = Sample.list();
63                        return;
64                }
65
66                // We expect the sample criteria to be the most discriminative, and discard
67                // the most samples. (e.g. by searching on sample title of sample type). For
68                // that reason we first look through the list of studies. However, when the
69                // user didn't enter any sample criteria, this will be an extra step, but doesn't
70                // cost much time to process.
71                def samples = []
72                if( getEntityCriteria( 'Study' ).size() > 0 ) {
73                        def studies = Study.findAll();
74                        if( studies.size() == 0 ) {
75                                results = [];
76                                return;
77                        }
78                        studies = filterOnStudyCriteria( studies );
79                       
80                        def c = Sample.createCriteria()
81                        samples = c.list {
82                                'in'( 'parent', studies )
83                        }
84                } else {
85                        Sample.findAll().each {
86                                samples << it;
87                        }
88                }
89
90                samples = filterOnSubjectCriteria( samples );
91                samples = filterOnSampleCriteria( samples );
92                samples = filterOnEventCriteria( samples );
93                samples = filterOnSamplingEventCriteria( samples );
94                samples = filterOnAssayCriteria( samples );
95
96                // Save matches
97                results = samples;
98        }
99
100        /**
101         * Filters the given list of samples on the sample criteria
102         * @param samples       Original list of samples
103         * @return                      List with all samples that match the Sample-criteria
104         */
105        protected List filterOnStudyCriteria( List studies ) {
106                return filterEntityList( studies, getEntityCriteria( 'Study' ), { study, criterion ->
107                        return criterion.matchOne( study );
108                });
109        }
110
111        /**
112         * Filters the given list of samples on the subject criteria
113         * @param samples       Original list of samples
114         * @return                      List with all samples that match the Subject-criteria
115         */
116        protected List filterOnSubjectCriteria( List samples ) {
117                return filterEntityList( samples, getEntityCriteria( 'Subject' ), { sample, criterion ->
118                        if( !sample.parentSubject )
119                                return false
120
121                        return criterion.matchOne( sample.parentSubject );
122                });
123        }
124
125        /**
126         * Filters the given list of samples on the sample criteria
127         * @param samples       Original list of samples
128         * @return                      List with all samples that match the sample-criteria
129         */
130        protected List filterOnSampleCriteria( List samples ) {
131                return filterEntityList( samples, getEntityCriteria( 'Sample' ), { sample, criterion ->
132                        if( !sample  )
133                                return false
134
135                        return criterion.matchOne( sample );
136                });
137        }
138
139        /**
140         * Filters the given list of samples on the event criteria
141         * @param samples       Original list of samples
142         * @return                      List with all samples that match the event-criteria
143         */
144        protected List filterOnEventCriteria( List samples ) {
145                return filterEntityList( samples, getEntityCriteria( 'Event' ), { sample, criterion ->
146                        if( !sample || !sample.parentEventGroup || !sample.parentEventGroup.events?.size() )
147                                return false
148
149                        return criterion.matchAny( sample.parentEventGroup.events );
150                });
151        }
152
153        /**
154         * Filters the given list of samples on the sampling event criteria
155         * @param samples       Original list of samples
156         * @return                      List with all samples that match the event-criteria
157         */
158        protected List filterOnSamplingEventCriteria( List samples ) {
159                return filterEntityList( samples, getEntityCriteria( 'SamplingEvent' ), { sample, criterion ->
160                        if( !sample.parentEvent )
161                                return false
162
163                        return criterion.matchOne( sample.parentEvent );
164                });
165        }
166
167
168        /**
169         * Filters the given list of samples on the assay criteria
170         * @param samples       Original list of samples
171         * @return                      List with all samples that match the assay-criteria
172         */
173        protected List filterOnAssayCriteria( List samples ) {
174                if( !samples?.size() )
175                        return [];
176
177                // There is no sample.assays property, so we have to look for assays another way: just find
178                // all assays that match the criteria
179                def assays = filterEntityList( Assay.list(), getEntityCriteria( 'Assay' ), { assay, criterion ->
180                        if( !assay )
181                                return false
182
183                        return criterion.matchOne( assay );
184                });
185               
186                // If no assays match these criteria, then no samples will match either
187                if( assays.size() == 0 )
188                        return [];
189                       
190                // Now filter the samples on whether they are attached to the filtered assays
191                return samples.findAll { sample ->
192                        if( !sample.parent )
193                                return false;
194                       
195                        def studyAssays = assays.findAll { it.parent.equals( sample.parent ); }
196                       
197                        // See if this sample is present in any of the matching assays. If so,
198                        // this sample matches the criteria
199                        for( def assay in studyAssays ) {
200                                if( assay.samples?.contains( sample ) ) 
201                                        return true;
202                        }
203                       
204                        return false;
205                }
206        }
207
208}
Note: See TracBrowser for help on using the repository browser.