Changeset 1424


Ignore:
Timestamp:
Jan 21, 2011, 4:30:04 PM (6 years ago)
Author:
robert@…
Message:

Improved querying and created a possibility to search for assays

Location:
trunk
Files:
6 added
4 deleted
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/query/AdvancedQueryController.groovy

    r1415 r1424  
    3636                // Create a search object and let it do the searching
    3737                Search search;
     38                String view;
    3839                switch( params.entity ) {
    39                         case "Study":   search = new StudySearch();             break;
    40                         case "Sample":  search = new SampleSearch();    break;
     40                        case "Study":   search = new StudySearch();             view = "studyresults";  break;
     41                        case "Sample":  search = new SampleSearch();    view = "sampleresults"; break;
    4142                       
    4243                        // This exception will only be thrown if the entitiesToSearchFor contains more entities than
     
    4748                search.execute( parseCriteria( params.criteria ) );
    4849               
    49                 render( view: search.getView(), model: [search: search] );
     50                render( view: view, model: [search: search] );
    5051        }
    5152       
     
    6465                                def templateFields = TemplateField.findAllByEntity( entity )
    6566                               
    66                                 fields[ it ] = ( domainFields + templateFields ).collect { it.name }.unique().sort { a, b -> a[0].toUpperCase() + a[1..-1] <=> b[0].toUpperCase() + b[1..-1] };
     67                                def fieldNames = ( domainFields + templateFields ).collect { it.name }.unique() + 'Template'
     68                               
     69                                fields[ it ] = fieldNames.sort { a, b -> a[0].toUpperCase() + a[1..-1] <=> b[0].toUpperCase() + b[1..-1] };
    6770                        }
    6871                }
     
    8689         *      ]
    8790         *
    88          * @return      List with [entity: ..., field: ..., entityfield: ..., operator: ..., value: ...] tuples.
     91         * @return      List with Criterion objects
    8992         */
    9093        protected List parseCriteria( def c ) {
     
    9497                c.each {
    9598                        if( it.key ==~ /[0-9]+/ ) {
    96                                 def criterium = it.value;
     99                                def formCriterion = it.value;
     100                                Criterion criterion = new Criterion();
    97101                               
    98                                 def field = criterium.entityfield?.split( /\./ );
     102                                // Split entity and field
     103                                def field = formCriterion.entityfield?.split( /\./ );
    99104                               
    100105                                if( field.size() > 1 ) {
    101                                         criterium.entity = field[0].toString();
    102                                         criterium.field = field[1].toString();
     106                                        criterion.entity = field[0].toString();
     107                                        criterion.field = field[1].toString();
    103108                                } else {
    104                                         criterium.entity = null;
    105                                         criterium.field = field;
     109                                        criterion.entity = null;
     110                                        criterion.field = field;
    106111                                }
    107112                               
    108                                 list << criterium;
     113                                // Convert operator string to Operator-enum field
     114                                switch( formCriterion.operator ) {
     115                                        case ">=":                      criterion.operator = Operator.gte; break;
     116                                        case ">":                       criterion.operator = Operator.gt;  break;
     117                                        case "<":                       criterion.operator = Operator.lte; break;
     118                                        case "<=":                      criterion.operator = Operator.lt;  break;
     119                                        case "contains":        criterion.operator = Operator.contains; break;
     120                                        case "equals":          criterion.operator = Operator.equals; break;
     121                                }
     122                               
     123                                // Copy value
     124                                criterion.value = formCriterion.value;
     125                                 
     126                                list << criterion;
    109127                        }
    110128                }
  • trunk/grails-app/domain/dbnp/studycapturing/RelTime.groovy

    r959 r1424  
    2121package dbnp.studycapturing
    2222
    23 class RelTime {
     23class RelTime implements Comparable {
    2424        final static long s = 1L;
    2525        final static long m = 60L * s;
     
    285285
    286286        public void computeDifference(Date start, Date end) {
    287                 println([start, end]);
    288                 println([start.getTime(), end.getTime()]);
    289 
    290287                if (start && end) {
    291288                        long seconds = (end.getTime() - start.getTime()) / 1000L;
     
    301298                return reltime;
    302299        }
     300       
     301        public boolean equals( Object o ) {
     302                if( o == null )
     303                        return false
     304                if( !( o instanceof RelTime ) )
     305                        return false
     306               
     307                RelTime rt = (RelTime) o;
     308               
     309                return rt.reltimeValue == this.reltimeValue;
     310        }
     311       
     312        public int compareTo( Object o ) throws ClassCastException {
     313                if( o == null || !( o instanceof RelTime ) )
     314                        throw new ClassCastException( "Can't cast object " + o + " of class " + o.class.getName() + " to RelTime for comparison.")
     315               
     316                RelTime rt = (RelTime) o;
     317               
     318                return rt.reltimeValue <=> this.reltimeValue;
     319        }
    303320}
  • trunk/grails-app/views/advancedQuery/index.gsp

    r1415 r1424  
    1313<form id="input_criteria">
    1414        <h2>Add criterium</h2>
     15        <p>
     16                N.B. Comparing numerical values is done without taking into
     17                account the units. E.g. a weight of 1 kg equals 1 grams.
     18        </p>
    1519        <label for="field">Field</label>
    1620                <select name="field">
     
    2731                </select>
    2832               
     33        <label for="value">Comparison</label>
     34                <select name="operator">
     35                        <option value="equals">Equals</option>
     36                        <option value="contains">Contains</option>
     37                        <option value="&gt;=">Greater than or equals</option>
     38                        <option value="&gt;">Greater than</option>
     39                        <option value="&lt;">Lower than</option>
     40                        <option value="&lt;=">Lower than or equals</option>
     41                </select>
     42
    2943        <label for="value">Value</label>
    3044                <input class='text' type="text" name="value" />
  • trunk/grails-app/views/advancedQuery/results.gsp

    r1415 r1424  
    1515</p>
    1616<ul id="criteria">
    17         <g:each in="${search.getCriteria()}" var="criterium">
     17        <g:each in="${search.getCriteria()}" var="criterion">
    1818                <li>
    19                         <span class="entityfield">${criterium.entityfield}</span>
    20                         <span class="operator">${criterium.operator}</span>
    21                         <span class="value">${criterium.value}</span>
     19                        <span class="entityfield">${criterion.entity}.${criterion.field}</span>
     20                        <span class="operator">${criterion.operator}</span>
     21                        <span class="value">${criterion.value}</span>
    2222                </li>
    2323        </g:each>
  • trunk/grails-app/views/advancedQuery/studyresults.gsp

    r1415 r1424  
    1515</p>
    1616<ul id="criteria">
    17         <g:each in="${search.getCriteria()}" var="criterium">
     17        <g:each in="${search.getCriteria()}" var="criterion">
    1818                <li>
    19                         <span class="entityfield">${criterium.entityfield}</span>
    20                         <span class="operator">${criterium.operator}</span>
    21                         <span class="value">${criterium.value}</span>
     19                        <span class="entityfield">${criterion.entity}.${criterion.field}</span>
     20                        <span class="operator">${criterion.operator}</span>
     21                        <span class="value">${criterion.value}</span>
    2222                </li>
    2323        </g:each>
  • trunk/src/groovy/dbnp/query/SampleSearch.groovy

    r1415 r1424  
    1515package dbnp.query
    1616
     17import java.util.List;
     18import dbnp.studycapturing.*;
     19
    1720class SampleSearch extends Search {
    1821        public SampleSearch() {
     
    2124
    2225        /**
    23          * Executes a search based on the given criteria. Should be filled in by
    24          * subclasses searching for a specific entity
     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         *     
    2555         */
    2656        @Override
    2757        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                });
    28185               
    29         }
     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
    30208}
  • trunk/src/groovy/dbnp/query/Search.groovy

    r1415 r1424  
    1616package dbnp.query
    1717
     18import dbnp.studycapturing.RelTime
     19import dbnp.studycapturing.TemplateEntity
     20import dbnp.studycapturing.TemplateFieldType
    1821import java.util.List;
     22import java.text.DateFormat;
     23import java.text.SimpleDateFormat
    1924
    2025class Search {
     
    2328        protected List criteria;
    2429        protected List results;
    25         protected String view = "results";
    2630
    2731        public List getCriteria() { return criteria; }
     
    3034        public List getResults() { return results; }
    3135        public void setResults( List r ) { results = r; }
    32 
    33         public String getView() { return view; }
    34         public void setView( String v) { view = v; }
    3536
    3637        /**
     
    7071                return criteria?.findAll { it.entity == entity }
    7172        }
    72 
     73       
    7374        /**
    74          * Filters a list with entities, based on the given criteria and a closure to check whether a criterium is matched
     75         * Filters a list with entities, based on the given criteria and a closure to check whether a criterion is matched
    7576         *
    7677         * @param entities      Original list with entities to check for these criteria
    7778         * @param criteria      List with criteria to match on
    78          * @param check         Closure to see whether a specific entity matches a criterium. Gets two arguments:
     79         * @param check         Closure to see whether a specific entity matches a criterion. Gets two arguments:
    7980         *                                              element         The element to check
    80          *                                              criterium       The criterium to check on.
    81          *                                      Returns true if the criterium holds, false otherwise
     81         *                                              criterion       The criterion to check on.
     82         *                                      Returns true if the criterion holds, false otherwise
    8283         * @return                      The filtered list of entities
    8384         */
    84         protected List filterEntityList( List entities, List criteria, Closure check ) {
     85        protected List filterEntityList( List entities, List<Criterion> criteria, Closure check ) {
    8586                if( !entities || !criteria || criteria.size() == 0 ) {
    8687                        return entities;
     
    8889
    8990                return entities.findAll { entity ->
    90                         for( def criterium in criteria ) {
    91                                 println "Check " + entity + " for " + criterium
    92                                 if( !check( entity, criterium ) ) {
     91                        for( criterion in criteria ) {
     92                                if( !check( entity, criterion ) ) {
    9393                                        return false;
    9494                                }
     
    9797                }
    9898        }
     99       
     100        /**
     101         * Prepares a value from a template entity for comparison, by giving it a correct type
     102         *
     103         * @param value         Value of the field
     104         * @param type          TemplateFieldType       Type of the specific field
     105         * @return                      The value of the field in the correct entity
     106         */
     107        public static def prepare( def value, TemplateFieldType type ) {
     108                switch (type) {
     109                        case TemplateFieldType.DATE:
     110                                try {
     111                                        return new SimpleDateFormat( "yyyy-MM-dd" ).parse( value )
     112                                } catch( Exception e ) {
     113                                        return value.toString();
     114                                }
     115                        case TemplateFieldType.RELTIME:
     116                                try {
     117                                        if( value instanceof Number ) {
     118                                                return new RelTime( value );
     119                                        } else if( value.toString().isNumber() ) {
     120                                                return new RelTime( Long.parseLong( value.toString() ) )
     121                                        } else {
     122                                                return new RelTime( value );
     123                                        }
     124                                } catch( Exception e ) {
     125                                        try {
     126                                                return Long.parseLong( value )
     127                                        } catch( Exception e2 ) {
     128                                                return value.toString();
     129                                        }
     130                                }
     131                        case TemplateFieldType.DOUBLE:
     132                                try {
     133                                        return Double.valueOf( value )
     134                                } catch( Exception e ) {
     135                                        return value.toString();
     136                                }
     137                        case TemplateFieldType.BOOLEAN:
     138                                try {
     139                                        return Boolean.valueOf( value )
     140                                } catch( Exception e ) {
     141                                        println e.getMessage();
     142                                        return value.toString();
     143                                }
     144                        case TemplateFieldType.LONG:
     145                                try {
     146                                        return Long.valueOf( value )
     147                                } catch( Exception e ) {
     148                                        return value.toString();
     149                                }
     150                        case TemplateFieldType.STRING:
     151                        case TemplateFieldType.TEXT:
     152                        case TemplateFieldType.STRINGLIST:
     153                        case TemplateFieldType.TEMPLATE:
     154                        case TemplateFieldType.MODULE:
     155                        case TemplateFieldType.FILE:
     156                        case TemplateFieldType.ONTOLOGYTERM:
     157                        default:
     158                                return value.toString();
     159                }
    99160
    100         /**
    101          * Tries to match a value against a criterium and returns true if it matches
    102          *
    103          * @param value         Value of the field to match
    104          * @param criterium     Criterium to match on. Should be a map with entries 'operator' and 'value'
    105          * @return                      True iff the value matches this criterium, false otherwise
    106          */
    107         protected boolean compare( def value, def criterium ) {
    108                 switch( value.class.getName() ) {
    109                         // TODO: Make the search capable of handle RelTime fields
    110                         case "java.lang.Long":                  return longCompare( value, criterium );
    111                         case "java.lang.Double":                return doubleCompare( value, criterium );
    112                         case "java.lang.Boolean":               return booleanCompare( value, criterium );
    113                         case "java.lang.Date":                  return dateCompare( value, criterium );
    114                         case "AssayModule":
    115                         case "Template":
    116                         case "RelTime":
    117                         case "Term":
    118                         case "TemplateFieldListItem":
    119                         default:                                                return stringCompare( value.toString(), criterium );
    120                 }
    121         }
    122 
    123         /**
    124          * Tries to match a string value against a criterium and returns true if it matches
    125          *
    126          * @param value         String value of the field to match
    127          * @param criterium     Criterium to match on. Should be a map with entries 'operator' and 'value'
    128          * @return                      True iff the value matches this criterium, false otherwise
    129          */
    130         protected boolean stringCompare( String value, def criterium ) {
    131                 try {
    132                         String stringCriterium = criterium.value.toString().trim()
    133                         return value.trim().equals( stringCriterium );
    134                 } catch( Exception e ) {
    135                         return false;
    136                 }
    137         }
    138 
    139         /**
    140          * Tries to match a date value against a criterium and returns true if it matches
    141          *
    142          * @param value         Date value of the field to match
    143          * @param criterium     Criterium to match on. Should be a map with entries 'operator' and 'value'
    144          * @return                      True iff the value matches this criterium, false otherwise
    145          */
    146         protected boolean dateCompare( Date value, def criterium ) {
    147                 try {
    148                         Date dateCriterium = DateFormat.parse( criterium.value );
    149                         return value.equals( dateCriterium );
    150                 } catch( Exception e ) {
    151                         return false;
    152                 }
    153         }
    154 
    155         /**
    156          * Tries to match a long value against a criterium and returns true if it matches
    157          *
    158          * @param value         Long value of the field to match
    159          * @param criterium     Criterium to match on. Should be a map with entries 'operator' and 'value'
    160          * @return                      True iff the value matches this criterium, false otherwise
    161          */
    162         protected boolean longCompare( Long value, def criterium ) {
    163                 try {
    164                         Long longCriterium = Long.parseLong( criterium.value );
    165                         return value.equals( longCriterium );
    166                 } catch( Exception e ) {
    167                         return false;
    168                 }
    169         }
    170 
    171         /**
    172          * Tries to match a double value against a criterium and returns true if it matches
    173          *
    174          * @param value         Double value of the field to match
    175          * @param criterium     Criterium to match on. Should be a map with entries 'operator' and 'value'
    176          * @return                      True iff the value matches this criterium, false otherwise
    177          */
    178         protected boolean doubleCompare( Double value, def criterium ) {
    179                 try {
    180                         Double doubleCriterium = Double.parseDouble( criterium.value );
    181                         return value.equals( doubleCriterium );
    182                 } catch( Exception e ) {
    183                         return false;
    184                 }
    185         }
    186 
    187 
    188         /**
    189          * Tries to match a boolean value against a criterium and returns true if it matches
    190          *
    191          * @param value         Boolean value of the field to match
    192          * @param criterium     Criterium to match on. Should be a map with entries 'operator' and 'value'
    193          * @return                      True iff the value matches this criterium, false otherwise
    194          */
    195         protected boolean booleanCompare( Double value, def criterium ) {
    196                 try {
    197                         Boolean booleanCriterium = Boolean.parseBoolean( criterium.value );
    198                         return value.equals( booleanCriterium );
    199                 } catch( Exception e ) {
    200                         return false;
    201                 }
    202161        }
    203162}
  • trunk/src/groovy/dbnp/query/StudySearch.groovy

    r1415 r1424  
    2020        public StudySearch() {
    2121                this.entity = "Study";
    22                 this.view = "studyresults";
    2322        }
    2423
     
    4645         * as well belong to a mouse subject and still the study satisfies the criteria.
    4746         *
    48          * When searching for more than one criterium per entity, these are taken combined. Searching for
     47         * When searching for more than one criterion per entity, these are taken combined. Searching for
    4948         *
    5049         *              Subject.species = 'human'
     
    5251         *
    5352         *  will result in all studies having a human subject named 'Jan'. Studies with only a mouse subject
    54          *  named 'Jan' or a human subject named 'Kees' won't satisty the criteria.
     53         *  named 'Jan' or a human subject named 'Kees' won't satisfy the criteria.
    5554         *     
    5655         */
     
    7170                studies = filterOnSampleCriteria( studies );
    7271                studies = filterOnEventCriteria( studies );
     72                studies = filterOnSamplingEventCriteria( studies );
    7373                studies = filterOnAssayCriteria( studies );
    7474
     
    8383         */
    8484        protected List filterOnStudyCriteria( List studies ) {
    85                 return filterEntityList( studies, getEntityCriteria( 'Study' ), { study, criterium ->
    86                         try {
    87                                 return this.compare( study.getFieldValue( criterium.field ), criterium );
    88                         } catch( Exception e ) {
    89                                 // An exception occurs if the given field doesn't exist. In that case, this criterium will fail.
    90                                 // TODO: Maybe give the user a choice whether he want's to include these studies or not
    91                                 return false;
    92                         }
     85                return filterEntityList( studies, getEntityCriteria( 'Study' ), { study, criterion ->
     86                        return criterion.matchOne( study );
    9387                });
    9488        }
     
    10094         */
    10195        protected List filterOnSubjectCriteria( List studies ) {
    102                 return filterEntityList( studies, getEntityCriteria( 'Subject' ), { study, criterium ->
     96                return filterEntityList( studies, getEntityCriteria( 'Subject' ), { study, criterion ->
    10397                        if( !study.subjects?.size() )
    10498                                return false
    10599
    106                         for( subject in study.subjects ) {
    107                                 try {
    108                                         if( this.compare( subject.getFieldValue( criterium.field ), criterium ) ) {
    109                                                 return true
    110                                         }
    111                                 } catch( Exception e ) {
    112                                         // An exception occurs if the given field doesn't exist. In that case, this criterium will fail.
    113                                         // TODO: Maybe give the user a choice whether he want's to include these studies or not
    114                                 }
    115                         }
    116                        
    117                         return false;
     100                        return criterion.matchAny( study.subjects );
    118101                });
    119102        }
     
    125108         */
    126109        protected List filterOnSampleCriteria( List studies ) {
    127                 return filterEntityList( studies, getEntityCriteria( 'Sample' ), { study, criterium ->
     110                return filterEntityList( studies, getEntityCriteria( 'Sample' ), { study, criterion ->
    128111                        if( !study.samples?.size() )
    129112                                return false
    130113
    131                         for( sample in study.samples ) {
    132                                 try {
    133                                         if( this.compare( sample.getFieldValue( criterium.field ), criterium ) )
    134                                                 return true
    135                                 } catch( Exception e ) {
    136                                         // An exception occurs if the given field doesn't exist. In that case, this criterium will fail.
    137                                         // TODO: Maybe give the user a choice whether he want's to include these studies or not
    138                                 }
    139                         }
    140                         return false;
    141                        
     114                        return criterion.matchAny( study.samples );
    142115                });
    143116        }
     
    149122         */
    150123        protected List filterOnEventCriteria( List studies ) {
    151                 return filterEntityList( studies, getEntityCriteria( 'Event' ), { study, criterium ->
     124                return filterEntityList( studies, getEntityCriteria( 'Event' ), { study, criterion ->
    152125                        if( !study.events?.size() )
    153126                                return false
    154127
    155                         for( event in study.events ) {
    156                                 try {
    157                                         if( this.compare( event.getFieldValue( criterium.field ), criterium ) )
    158                                                 return true
    159                                 } catch( Exception e ) {
    160                                         // An exception occurs if the given field doesn't exist. In that case, this criterium will fail.
    161                                         // TODO: Maybe give the user a choice whether he want's to include these studies or not
    162                                 }
    163                         }
    164                         return false;
     128                        return criterion.matchAny( study.events );
    165129                });
    166130        }
    167131       
     132        /**
     133        * Filters the given list of studies on the sampling event criteria
     134        * @param studies        Original list of studies
     135        * @return                       List with all studies that match the event-criteria
     136        */
     137   protected List filterOnSamplingEventCriteria( List studies ) {
     138           return filterEntityList( studies, getEntityCriteria( 'SamplingEvent' ), { study, criterion ->
     139                   if( !study.samplingEvents?.size() )
     140                           return false
     141
     142                        return criterion.matchAny( study.samplingEvents );
     143           });
     144   }
     145
    168146       
    169147        /**
     
    173151         */
    174152        protected List filterOnAssayCriteria( List studies ) {
    175                 return filterEntityList( studies, getEntityCriteria( 'Assay' ), { study, criterium ->
     153                return filterEntityList( studies, getEntityCriteria( 'Assay' ), { study, criterion ->
    176154                        if( !study.assays?.size() )
    177155                                return false
    178156
    179                         for( assay in study.assays ) {
    180                                 try {
    181                                         if( this.compare( assay.getFieldValue( criterium.field ), criterium ) )
    182                                                 return true
    183                                 } catch( Exception e ) {
    184                                         // An exception occurs if the given field doesn't exist. In that case, this criterium will fail.
    185                                         // TODO: Maybe give the user a choice whether he want's to include these studies or not
    186                                 }
    187                         }
    188                         return false;
     157                        return criterion.matchAny( study.assays );
    189158                });
    190159        }
  • trunk/test/unit/dbnp/query/SearchTests.groovy

    r1415 r1424  
    11package dbnp.query
    22
     3import dbnp.studycapturing.RelTime
     4import dbnp.studycapturing.TemplateFieldType;
    35import grails.test.*
    46
     
    2022    protected void setUp() {
    2123        super.setUp()
     24                mockLogging( Search );
    2225    }
    2326
     
    2629    }
    2730
    28     void testSomething() {
     31    void testPrepare() {
     32                // Test prepare method for dates
     33                Date d = Date.parse( "yyyy-MM-dd", "1982-10-21" );
     34                assert !d.equals( Search.prepare( "21-10-1982", TemplateFieldType.DATE ) )
     35                assert !d.equals( Search.prepare( "21-10-82", TemplateFieldType.DATE ) )
     36                assert d.equals( Search.prepare( "1982-10-21 00:00:00", TemplateFieldType.DATE ) )
     37                assert d.equals( Search.prepare( "1982-10-21", TemplateFieldType.DATE ) )
     38               
     39                // Test prepare method for RelTime
     40                assertEquals new RelTime( 0 ), Search.prepare( "", TemplateFieldType.RELTIME )
     41                assertEquals new RelTime( 3600 ), Search.prepare( "1h", TemplateFieldType.RELTIME )
     42                assertEquals new RelTime( 3600 ), Search.prepare( "60m", TemplateFieldType.RELTIME )
     43                assertEquals new RelTime( 3600 ), Search.prepare( "3600", TemplateFieldType.RELTIME )
     44                assertEquals "abc", Search.prepare( "abc", TemplateFieldType.RELTIME )
     45               
     46                // Test prepare method for Double
     47                assertEquals new Double( 100.1 ), Search.prepare( "100.1", TemplateFieldType.DOUBLE )
     48                assertEquals new Double( 0.0 ), Search.prepare( "0", TemplateFieldType.DOUBLE )
     49                assertEquals new Double( 100.0 ), Search.prepare( "100", TemplateFieldType.DOUBLE )
     50                assertEquals new Double( -100.1 ), Search.prepare( "-100.1", TemplateFieldType.DOUBLE )
     51               
     52                // Test prepare method for Long
     53                assertEquals new Long( 100 ), Search.prepare( "100", TemplateFieldType.LONG )
     54                assertEquals new Long( 0 ), Search.prepare( "0", TemplateFieldType.LONG )
     55                assertEquals new Long( -100 ), Search.prepare( "-100", TemplateFieldType.LONG )
     56                assertEquals "3.8", Search.prepare( "3.8", TemplateFieldType.LONG )     // Can't be parsed into long
     57                assertEquals "4.2", Search.prepare( "4.2", TemplateFieldType.LONG )     // Can't be parsed into long
     58               
     59                // Test prepare method for Boolean
     60                assertEquals Boolean.TRUE, Search.prepare( "true", TemplateFieldType.BOOLEAN )
     61                assertEquals Boolean.FALSE, Search.prepare( "false", TemplateFieldType.BOOLEAN )
     62                assertEquals Boolean.FALSE, Search.prepare( "", TemplateFieldType.BOOLEAN )
     63                assertEquals Boolean.FALSE, Search.prepare( "test", TemplateFieldType.BOOLEAN )
     64    }
    2965
    30     }
    3166}
  • trunk/web-app/css/advancedQuery.css

    r1415 r1424  
    1313#searchForm ul#criteria li:hover span { text-decoration: line-through; }
    1414
    15 #input_criteria { display: block; float: right; width: 250px; border: 1px solid #666; padding: 10px; }
     15#input_criteria { display: block; float: right; width: 260px; border: 1px solid #666; padding: 10px; }
    1616#input_criteria h2 { margin-top: 2px; margin-bottom: 8px; }
    17 #input_criteria label { width: 70px; margin-top: 8px; }
     17#input_criteria label { width: 80px; margin-top: 8px; }
    1818#input_criteria input.text, #input_criteria select { width: 165px; }
    1919#input_criteria input.button {  margin-top: 8px; }
  • trunk/web-app/js/advancedQuery.js

    r1415 r1424  
    88        var field_descriptor = $( '#input_criteria select[name=field]' ).val();
    99        var value = $( '#input_criteria input[name=value]' ).val();
    10         var operator = 'equals';
     10        var operator = $( '#input_criteria select[name=operator]' ).val();
    1111       
    1212        // Show the title and a remove button
     
    1919        // Clear the input form
    2020        $( '#input_criteria select[name=field]' ).val( '' );
     21        $( '#input_criteria select[name=operator]' ).val( 'equals' );
    2122        $( '#input_criteria input[name=value]' ).val( '' );
    2223}
Note: See TracChangeset for help on using the changeset viewer.