Changeset 1526

Show
Ignore:
Timestamp:
16-02-11 11:12:14 (3 years ago)
Author:
robert@…
Message:

Added assay search and improved query form

Location:
trunk
Files:
2 added
14 modified

Legend:

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

    r1524 r1526  
    1515        def authenticationService 
    1616 
    17         def entitiesToSearchFor = [ 'Study': 'Studies', 'Sample': 'Samples'] 
     17        def entitiesToSearchFor = [ 'Study': 'Studies', 'Sample': 'Samples', 'Assay': 'Assays'] 
    1818 
    1919        /** 
     
    198198 
    199199                if( queryIds.size() == 0 ) { 
    200                         flash.error = "Incorrect search ID given to show" 
    201                         redirect( action: "index" ); 
     200                        flash.error = "Incorrect search ID given to search in" 
     201                        redirect( action: "list" ); 
    202202                        return 
    203203                } 
     
    287287                        case "Study":   return "studyresults";  break; 
    288288                        case "Sample":  return "sampleresults"; break; 
     289                        case "Assay":   return "assayresults";  break; 
    289290                        default:                return "results"; break; 
    290291                } 
     
    298299                        case "Study":   return new StudySearch(); 
    299300                        case "Sample":  return new SampleSearch(); 
    300  
     301                        case "Assay":   return new AssaySearch(); 
     302                         
    301303                        // This exception will only be thrown if the entitiesToSearchFor contains more entities than 
    302304                        // mentioned in this switch structure. 
     
    375377                // Loop through all keys of c and remove the non-numeric ones 
    376378                for( c in formCriteria ) { 
    377                         if( c.key ==~ /[0-9]+/ ) { 
     379                        if( c.key ==~ /[0-9]+/ && c.value.entityfield ) { 
    378380                                def formCriterion = c.value; 
    379381 
     
    478480 
    479481                // First check whether a search with the same criteria is already present 
    480                 def previousSearch = retrieveSearchByCriteria( s.getCriteria(), s.searchMode ); 
     482                def previousSearch = retrieveSearch( s ); 
    481483 
    482484                def id 
     
    496498        /** 
    497499         * Retrieves a search from session with the same criteria as given 
    498          * @param criteria      List of criteria to search for 
     500         * @param s                     Search that is used as an example to search for 
    499501         * @return                      Search that has this criteria, or null if no such search is found. 
    500502         */ 
    501         protected Search retrieveSearchByCriteria( List criteria, SearchMode searchMode = SearchMode.and ) { 
     503        protected Search retrieveSearch( Search s ) { 
    502504                if( !session.queries ) 
    503505                        return null 
    504506 
    505                 if( !criteria ) 
    506                         return null 
    507  
    508507                for( query in session.queries ) { 
    509                         def key = query.key; 
    510508                        def value = query.value; 
    511509 
    512                         if( value.searchMode == searchMode && value.criteria && value.criteria.containsAll( criteria ) && criteria.containsAll( value.criteria ) ) { 
    513                                 return value; 
    514                         } 
     510                        if( s.equals( value ) ) 
     511                                return value 
    515512                } 
    516513 
  • trunk/grails-app/domain/dbnp/studycapturing/Assay.groovy

    r1457 r1526  
    7474         
    7575        /** 
     76         * Basic equals method to check whether objects are equals, by comparing the ids 
     77         * @param o             Object to compare with 
     78         * @return              True iff the id of the given Study is equal to the id of this Study 
     79         */ 
     80        public boolean equals( Object o ) { 
     81                if( o == null ) 
     82                        return false; 
     83 
     84                if( !( o instanceof Assay ) ) 
     85                        return false 
     86 
     87                Assay s = (Assay) o; 
     88 
     89                return this.id == s.id 
     90        } 
     91         
     92        /** 
    7693         * Returns the UUID of this sample and generates one if needed 
    7794         */ 
  • trunk/grails-app/views/advancedQuery/_criteria.gsp

    r1512 r1526  
    11<%@ page import="dbnp.query.*" %> 
    2 <ul id="criteria"> 
    3         <g:each in="${criteria}" var="criterion" status="j"> 
    4                 <li> 
    5                         <span class="entityfield">${criterion.entityField().toLowerCase()}</span> 
    6                         <span class="operator">${criterion.operator}</span> 
    7                         <span class="value"> 
    8                                 <g:if test="${criterion.value != null && criterion.value instanceof Search}"> 
    9                                         <g:link action="show" id="${criterion.value.id}">${criterion.value}</g:link> 
     2<g:if test="${criteria}"> 
     3        with  
     4        <ul id="criteria"> 
     5                <g:each in="${criteria}" var="criterion" status="j"> 
     6                        <li> 
     7                                <span class="entityfield">${criterion.entityField().toLowerCase()}</span> 
     8                                <span class="operator">${criterion.operator}</span> 
     9                                <span class="value"> 
     10                                        <g:if test="${criterion.value != null && criterion.value instanceof Search}"> 
     11                                                <g:link action="show" id="${criterion.value.id}">${criterion.value}</g:link> 
     12                                        </g:if> 
     13                                        <g:else> 
     14                                                ${criterion.value} 
     15                                        </g:else> 
     16                                </span> 
     17                                <g:if test="${j < criteria.size() -1}"> 
     18                                        <g:if test="${search.searchMode == SearchMode.and}">and</g:if> 
     19                                        <g:if test="${search.searchMode == SearchMode.or}">or</g:if> 
    1020                                </g:if> 
    11                                 <g:else> 
    12                                         ${criterion.value} 
    13                                 </g:else> 
    14                         </span> 
    15                         <g:if test="${j < criteria.size() -1}"> 
    16                                 <g:if test="${search.searchMode == SearchMode.and}">and</g:if> 
    17                                 <g:if test="${search.searchMode == SearchMode.or}">or</g:if> 
    18                         </g:if> 
    19                 </li> 
    20         </g:each> 
    21 </ul> 
     21                        </li> 
     22                </g:each> 
     23        </ul> 
     24</g:if> 
     25<g:else> 
     26        without criteria. 
     27</g:else> 
  • trunk/grails-app/views/advancedQuery/index.gsp

    r1512 r1526  
    3030                                        showCriterium("${criterion.entityField().encodeAsJavaScript()}", "${criterion.value.toString().encodeAsJavaScript()}", "${criterion.operator.toString().encodeAsJavaScript()}"); 
    3131                                </g:each> 
    32                                 showHideNoCriteriaItem(); 
    3332                        }); 
    3433                </g:if> 
     
    5150 
    5251<div id="searchForm"> 
    53         <form id="input_criteria"> 
    54         <h2>Add criterium</h2> 
    55         <p class="explanation"> 
    56                 N.B. Comparing numerical values is done without taking into 
    57                 account the units. E.g. a weight of 1 kg equals 1 grams. 
    58         </p> 
    59         <label for="field">Field</label> 
    60                 <select name="field" id="queryFieldSelect"> 
    61                         <option value=""></option> 
    62                         <g:each in="${searchableFields}" var="entity"> 
    63                                 <optgroup label="${entity.key}"> 
    64                                         <g:each in="${entity.value}" var="field"> 
    65                                                 <option value="${entity.key}.${field}"> 
    66                                                         ${field[0].toUpperCase() + field[1..-1]} 
    67                                                 </option> 
    68                                         </g:each> 
    69                                 </optgroup> 
    70                         </g:each> 
    71                 </select> 
    72                  
    73         <label for="value">Comparison</label> 
    74                 <select name="operator"> 
    75                         <option value="equals">Equals</option> 
    76                         <option value="contains">Contains</option> 
    77                         <option value="&gt;=">Greater than or equals</option> 
    78                         <option value="&gt;">Greater than</option> 
    79                         <option value="&lt;">Lower than</option> 
    80                         <option value="&lt;=">Lower than or equals</option> 
    81                 </select> 
    82          
    83         <label for="value">Value</label> 
    84                 <input class='text' type="text" name="value" /> 
    85          
    86         <input class="button" type="button" onClick="addCriterium();" value="Add" /> 
    87         </form> 
    8852        <g:form action="search" method="get"> 
    89                 <label for="entity">Search for</label><g:select from="${entitiesToSearchFor}" optionKey="key" optionValue="value" name="entity" /><br /> 
    90                 <label for="entity">Searchtype</label><g:select from="${searchModes}" name="operator" /><br /> 
    91                 <label for="criteria">Criteria</label> 
     53 
     54                <h3><span class="nummer">1</span>Select criteria</h3> 
     55                <p class="explanation"> 
     56                        N.B. Comparing numerical values is done without taking into 
     57                        account the units. E.g. a weight of 1 kg equals 1 grams. 
     58                </p> 
    9259                <ul id="criteria"> 
    93                         <li class="emptyList">No criteria added. Use the form on the right to specify criteria to search on.</li> 
     60                        <li class="titlerow"> 
     61                                <span class="entityfield"> 
     62                                        Field 
     63                                </span> 
     64                                <span class="operator"> 
     65                                        Operator 
     66                                </span> 
     67                                <span class="value"> 
     68                                        Value 
     69                                </span> 
     70                        </li> 
     71                        <li class="newCriterion"> 
     72                                <span class="entityfield"> 
     73                                        <select name="criteria.0.entityfield" id="queryFieldSelect"> 
     74                                                <option value=""></option> 
     75                                                <g:each in="${searchableFields}" var="entity"> 
     76                                                        <optgroup label="${entity.key}"> 
     77                                                                <g:each in="${entity.value}" var="field"> 
     78                                                                        <option value="${entity.key}.${field}"> 
     79                                                                                ${field[0].toUpperCase() + field[1..-1]} 
     80                                                                        </option> 
     81                                                                </g:each> 
     82                                                        </optgroup> 
     83                                                </g:each> 
     84                                        </select> 
     85                                </span> 
     86                                <span class="operator"> 
     87                                        <select id="operator" name="criteria.0.operator"> 
     88                                                <option value="equals">Equals</option> 
     89                                                <option value="contains">Contains</option> 
     90                                                <option value="&gt;=">&gt;=</option> 
     91                                                <option value="&gt;">&gt;</option> 
     92                                                <option value="&lt;">&lt;</option> 
     93                                                <option value="&lt;=">&lt;=</option> 
     94                                        </select> 
     95                                </span> 
     96                                <span class="value"> 
     97                                        <input class='text' type="text" id="value" name="criteria.0.value" /> 
     98                                </span> 
     99                                <span class="addButton"> 
     100                                        <a href="#" onClick="addCriterion(); return false;"> 
     101                                                <img src="${fam.icon( name: 'add' )}" border="0"> 
     102                                        </a> 
     103                                </span> 
     104                        </li> 
    94105                </ul> 
    95106                 
    96                 <input type="submit" value="Run query" class="submitcriteria" disabled="disabled" /> 
     107                <div id="searchMode"> 
     108                        <h3><span class="nummer">1b</span>Search mode</h3> 
     109                        <p> 
     110                                Choose how to combine the given criteria:<br /> 
     111                                <g:select from="${searchModes}" name="operator" /> 
     112                        </p> 
     113                </div> 
     114                 
     115                <h3><span class="nummer">2</span>Output type</h3> 
     116                <p> 
     117                        Choose the type of output:<br /> 
     118                        <g:select from="${entitiesToSearchFor}" optionKey="key" optionValue="value" name="entity" /> 
     119                </p> 
     120 
     121                <h3><span class="nummer">3</span>Run query</h3> 
     122                <p> 
     123                        <input type="submit" value="Run query" class="submitcriteria" /> 
     124                </p> 
    97125        </g:form> 
    98126         
  • trunk/grails-app/views/advancedQuery/list.gsp

    r1524 r1526  
    5656                                <td>${search.entity}</td> 
    5757                                <td> 
    58                                         <g:each in="${search.getCriteria()}" var="criterion" status="j"> 
    59                                                 <g:if test="${j > 0}">, </g:if> 
     58                                        <g:set var="criteria" value="${search.getCriteria()}" /> 
     59                                        <g:each in="${criteria}" var="criterion" status="j"> 
    6060                                                <span class="entityfield">${criterion.entityField()}</span> 
    6161                                                <span class="operator">${criterion.operator}</span> 
     
    6868                                                        </g:else> 
    6969                                                </span> 
     70                                                <g:if test="${j < criteria.size() -1}"> 
     71                                                        <g:if test="${search.searchMode == SearchMode.and}">and</g:if> 
     72                                                        <g:if test="${search.searchMode == SearchMode.or}">or</g:if> 
     73                                                </g:if>                                          
    7074                                        </g:each> 
    7175                                </td> 
  • trunk/grails-app/views/advancedQuery/results.gsp

    r1524 r1526  
    1212 
    1313<div class="searchoptions"> 
    14         ${search.getNumResults()} <g:if test="${search.getNumResults() == 1}">result</g:if><g:else>results</g:else> found with  
     14        ${search.getNumResults()} <g:if test="${search.getNumResults() == 1}">result</g:if><g:else>results</g:else> found  
    1515        <g:render template="criteria" model="[criteria: search.getCriteria()]" /> 
    1616</div> 
     
    4949                                                        if( fieldValue ) {  
    5050                                                                if( fieldValue instanceof Collection ) { 
    51                                                                         fieldValue = fieldValue.collect { it.toString() }.findAll { it }.join( ', ' ); 
     51                                                                        fieldValue = fieldValue.collect { it.toString() }.findAll { it }.unique().join( ', ' ); 
    5252                                                                } else { 
    5353                                                                        fieldValue = fieldValue.toString(); 
  • trunk/grails-app/views/advancedQuery/sampleresults.gsp

    r1524 r1526  
    1212 
    1313<div class="searchoptions"> 
    14         ${search.getNumResults()} <g:if test="${search.getNumResults() == 1}">sample</g:if><g:else>samples</g:else> found with  
     14        ${search.getNumResults()} <g:if test="${search.getNumResults() == 1}">sample</g:if><g:else>samples</g:else> found  
    1515        <g:render template="criteria" model="[criteria: search.getCriteria()]" /> 
    1616</div> 
     
    5050                                                        if( fieldValue ) {  
    5151                                                                if( fieldValue instanceof Collection ) { 
    52                                                                         fieldValue = fieldValue.collect { it.toString() }.findAll { it }.join( ', ' ); 
     52                                                                        fieldValue = fieldValue.collect { it.toString() }.findAll { it }.unique().join( ', ' ); 
    5353                                                                } else { 
    5454                                                                        fieldValue = fieldValue.toString(); 
  • trunk/grails-app/views/advancedQuery/studyresults.gsp

    r1524 r1526  
    1212 
    1313<div class="searchoptions"> 
    14         ${search.getNumResults()} <g:if test="${search.getNumResults() == 1}">study</g:if><g:else>studies</g:else> found with  
     14        ${search.getNumResults()} <g:if test="${search.getNumResults() == 1}">study</g:if><g:else>studies</g:else> found  
    1515        <g:render template="criteria" model="[criteria: search.getCriteria()]" /> 
    1616</div> 
     
    8686                                                        if( fieldValue ) {  
    8787                                                                if( fieldValue instanceof Collection ) { 
    88                                                                         fieldValue = fieldValue.collect { it.toString() }.findAll { it }.join( ', ' ); 
     88                                                                        fieldValue = fieldValue.collect { it.toString() }.findAll { it }.unique().join( ', ' ); 
    8989                                                                } else { 
    9090                                                                        fieldValue = fieldValue.toString(); 
  • trunk/grails-app/views/study/show_assays.gsp

    r1490 r1526  
    3333                  <td> 
    3434                        <g:if test="${assay.module.openInFrame == null || assay.module.openInFrame == Boolean.TRUE}"> 
    35                   <jumpbar:link frameSource="${assay.module.url}/assay/showByToken/${assay.giveUUID()}" pageTitle="Metabolomics Module"> 
     35                  <jumpbar:link frameSource="${assay.module.url}/assay/showByToken/${assay.giveUUID()}" pageTitle="${assay.module.name}"> 
    3636                                view 
    3737                          </jumpbar:link> 
  • trunk/src/groovy/dbnp/query/SampleSearch.groovy

    r1524 r1526  
    7171                } 
    7272 
    73                 // We expect the sample criteria to be the most discriminative, and discard 
    74                 // the most samples. (e.g. by searching on sample title of sample type). For 
     73                // We expect the study criteria to be the most discriminative, and discard 
     74                // the most samples. (e.g. by searching on study title or study type). For 
    7575                // that reason we first look through the list of studies. However, when the 
    76                 // user didn't enter any sample criteria, this will be an extra step, but doesn't 
     76                // user didn't enter any study criteria, this will be an extra step, but doesn't 
    7777                // cost much time to process. 
    7878                def samples = [] 
     
    152152        @Override 
    153153        void executeOr() { 
    154                 // We expect the sample criteria to be the most discriminative, and discard 
    155                 // the most samples. (e.g. by searching on sample title of sample type). For 
    156                 // that reason we first look through the list of studies. However, when the 
    157                 // user didn't enter any sample criteria, this will be an extra step, but doesn't 
    158                 // cost much time to process. 
    159                 def samples = [] 
    160154                def allSamples = Sample.list().findAll { it.parent?.canRead( this.user ) }.toList(); 
    161  
    162                 // If no criteria are found, return all samples 
    163                 if( !criteria || criteria.size() == 0 ) { 
    164                         results = allSamples 
    165                         return; 
    166                 } 
    167  
    168                 samples = ( samples + filterOnStudyCriteria( allSamples - samples ) ).unique(); 
    169                 samples = ( samples + filterOnSubjectCriteria( allSamples - samples ) ).unique(); 
    170                 samples = ( samples + filterOnSampleCriteria( allSamples - samples ) ).unique(); 
    171                 samples = ( samples + filterOnEventCriteria( allSamples - samples ) ).unique(); 
    172                 samples = ( samples + filterOnSamplingEventCriteria( allSamples - samples ) ).unique(); 
    173                 samples = ( samples + filterOnAssayCriteria( allSamples - samples ) ).unique(); 
    174  
    175                 samples = ( samples + filterOnModuleCriteria( allSamples - samples ) ).unique(); 
    176  
    177                 // Save matches 
    178                 results = samples; 
     155                executeOr( allSamples ); 
    179156        } 
    180157 
     
    203180                                                return null 
    204181 
    205                                         return criterion.getFieldValue( sample.parentEventGroup.events.toList() ); 
     182                                        return sample.parentEventGroup.events?.collect { criterion.getFieldValue( it ) }; 
    206183                                } 
    207184                        case "SamplingEvent": 
     
    258235                }); 
    259236 
     237                println "Matching assays: " + assays 
     238         
    260239                // If no assays match these criteria, then no samples will match either 
    261240                if( assays.size() == 0 ) 
     
    268247 
    269248                        def studyAssays = assays.findAll { it.parent.equals( sample.parent ); } 
    270  
     249                         
     250                        println "Assays for " + sample + " (based on study): " + studyAssays 
     251                         
    271252                        // See if this sample is present in any of the matching assays. If so, 
    272253                        // this sample matches the criteria 
     
    274255                                if( assay.samples?.contains( sample ) ) 
    275256                                        return true; 
     257                                 
     258                                println "Assay " + assay + " with samples " + assay.samples + " doesn't contain " + sample; 
    276259                        } 
    277260 
  • trunk/src/groovy/dbnp/query/Search.groovy

    r1524 r1526  
    7171 
    7272        /** 
    73          * Returns a list of Criteria 
    74          */ 
    75         public List getCriteria() { return criteria; } 
    76  
    77         /** 
    78          * Sets a new list of criteria 
    79          * @param c     List with criteria objects 
    80          */ 
    81         public void setCriteria( List c ) { criteria = c; } 
    82  
    83         /** 
    84          * Adds a criterion to this query 
    85          * @param c     Criterion 
    86          */ 
    87         public void addCriterion( Criterion c ) { 
    88                 if( criteria ) 
    89                         criteria << c; 
    90                 else 
    91                         criteria = [c]; 
    92         } 
    93  
    94         /** 
    95          * Retrieves the results found using this query. The result is empty is  
    96          * the query has not been executed yet. 
    97          */ 
    98         public List getResults() { return results; } 
    99  
    100         /** 
    101          * Returns the results found using this query, filtered by a list of ids. 
    102          * @param selectedIds   List with ids of the entities you want to return. 
    103          * @return      A list with only those results for which the id is in the selectedIds 
    104          */ 
    105         public List filterResults( List selectedIds ) { 
    106                 if( !selectedIds || !results ) 
    107                         return results 
    108  
    109                 return results.findAll { 
    110                         selectedIds.contains( it.id ) 
    111                 } 
    112         } 
    113  
    114         /** 
    115          * Returns a list of fields for the results of this query. The fields returned are those 
    116          * fields that the query searched for.  
    117          */ 
    118         public Map getResultFields() { return resultFields; } 
    119  
    120         /** 
    12173         * Constructor of this search object. Sets the user field to the  
    12274         * currently logged in user 
     
    179131         * subclasses searching for a specific entity 
    180132         */ 
    181         public void executeAnd() { 
     133        protected void executeAnd() { 
    182134 
    183135        } 
     
    187139         * subclasses searching for a specific entity 
    188140         */ 
    189         public void executeOr() { 
    190  
    191         } 
    192  
     141        protected void executeOr() { 
     142 
     143        } 
     144 
     145        /** 
     146         * Default implementation of an inclusive (AND) search. Can be called by subclasses in order 
     147         * to simplify searches. 
     148         *  
     149         * Filters the list of objects on study, subject, sample, event, samplingevent and assaycriteria, 
     150         * based on the closures defined in valueCallback. Afterwards, the objects are filtered on module 
     151         * criteria 
     152         *  
     153         * @param objects       List of objects to search in 
     154         */ 
     155        protected void executeAnd( List objects ) { 
     156                // If no criteria are found, return all studies 
     157                if( !criteria || criteria.size() == 0 ) { 
     158                        results = objects; 
     159                        return; 
     160                } 
     161 
     162                // Perform filters 
     163                objects = filterOnStudyCriteria( objects ); 
     164                objects = filterOnSubjectCriteria( objects ); 
     165                objects = filterOnSampleCriteria( objects ); 
     166                objects = filterOnEventCriteria( objects ); 
     167                objects = filterOnSamplingEventCriteria( objects ); 
     168                objects = filterOnAssayCriteria( objects ); 
     169 
     170                objects = filterOnModuleCriteria( objects ); 
     171 
     172                // Save matches 
     173                results = objects; 
     174        } 
     175 
     176        /** 
     177        * Default implementation of an exclusive (OR) search. Can be called by subclasses in order 
     178        * to simplify searches. 
     179        * 
     180        * Filters the list of objects on study, subject, sample, event, samplingevent and assaycriteria, 
     181        * based on the closures defined in valueCallback. Afterwards, the objects are filtered on module 
     182        * criteria 
     183        * 
     184        * @param allObjects     List of objects to search in 
     185        */ 
     186   protected void executeOr( List allObjects ) { 
     187                // If no criteria are found, return all studies 
     188                if( !criteria || criteria.size() == 0 ) { 
     189                        results = allObjects; 
     190                        return; 
     191                } 
     192 
     193                // Perform filters on those objects not yet found by other criteria 
     194                def objects = [] 
     195                objects = ( objects + filterOnStudyCriteria( allObjects - objects ) ).unique(); 
     196                objects = ( objects + filterOnSubjectCriteria( allObjects - objects ) ).unique(); 
     197                objects = ( objects + filterOnSampleCriteria( allObjects - objects ) ).unique(); 
     198                objects = ( objects + filterOnEventCriteria( allObjects - objects ) ).unique(); 
     199                objects = ( objects + filterOnSamplingEventCriteria( allObjects - objects ) ).unique(); 
     200                objects = ( objects + filterOnAssayCriteria( allObjects - objects ) ).unique(); 
     201                 
     202                // All objects (including the ones already found by another criterion) are sent to 
     203                // be filtered on module criteria, in order to have the module give data about all 
     204                // objects (for showing purposes later on) 
     205                objects = ( objects + filterOnModuleCriteria( allObjects ) ).unique(); 
     206                 
     207                // Save matches 
     208                results = objects; 
     209   } 
     210 
     211                 
    193212        /************************************************************************ 
    194213         *  
    195          * These methods are used in querying and should be overridden by subclasses 
     214         * These methods are used in querying and can be overridden by subclasses 
    196215         * in order to provide custom searching 
    197216         *  
    198          */ 
     217         ************************************************************************/ 
    199218 
    200219        /** 
     
    270289                return criteria?.findAll { it.entity == entity } 
    271290        } 
    272  
    273         /** 
    274          * Filters a list with entities, based on the given criteria and a closure to check whether a criterion is matched 
    275          *  
    276          * @param entities      Original list with entities to check for these criteria 
    277          * @param criteria      List with criteria to match on 
    278          * @param check         Closure to see whether a specific entity matches a criterion. Gets two arguments: 
    279          *                                              element         The element to check  
    280          *                                              criterion       The criterion to check on. 
    281          *                                      Returns true if the criterion holds, false otherwise 
    282          * @return                      The filtered list of entities 
    283          */ 
    284         protected List filterEntityList( List entities, List<Criterion> criteria, Closure check ) { 
    285                 if( !entities || !criteria || criteria.size() == 0 ) { 
    286                         if( searchMode == SearchMode.and ) 
    287                                 return entities; 
    288                         else if( searchMode == SearchMode.or ) 
    289                                 return [] 
    290                 } 
    291  
    292                 return entities.findAll { entity -> 
    293                         if( searchMode == SearchMode.and ) { 
    294                                 for( criterion in criteria ) { 
    295                                         if( !check( entity, criterion ) ) { 
    296                                                 return false; 
    297                                         } 
    298                                 } 
    299                                 return true; 
    300                         } else if( searchMode == SearchMode.or ) { 
    301                                 for( criterion in criteria ) { 
    302                                         if( check( entity, criterion ) ) { 
    303                                                 return true; 
    304                                         } 
    305                                 } 
    306                                 return false; 
    307                         } 
    308                 } 
    309         } 
    310  
     291         
     292         
    311293        /** 
    312294         * Prepares a value from a template entity for comparison, by giving it a correct type 
    313295         * 
    314          * @param value         Value of the field  
     296         * @param value         Value of the field 
    315297         * @param type          TemplateFieldType       Type of the specific field 
    316298         * @return                      The value of the field in the correct entity 
     
    374356        } 
    375357 
     358        /***************************************************** 
     359        * 
     360        * Methods for filtering lists based on specific (GSCF) criteria 
     361        * 
     362        *****************************************************/ 
     363 
     364         
     365        /** 
     366         * Filters a list with entities, based on the given criteria and a closure to check whether a criterion is matched 
     367         * 
     368         * @param entities      Original list with entities to check for these criteria 
     369         * @param criteria      List with criteria to match on 
     370         * @param check         Closure to see whether a specific entity matches a criterion. Gets two arguments: 
     371         *                                              element         The element to check 
     372         *                                              criterion       The criterion to check on. 
     373         *                                      Returns true if the criterion holds, false otherwise 
     374         * @return                      The filtered list of entities 
     375         */ 
     376        protected List filterEntityList( List entities, List<Criterion> criteria, Closure check ) { 
     377                if( !entities || !criteria || criteria.size() == 0 ) { 
     378                        if( searchMode == SearchMode.and ) 
     379                                return entities; 
     380                        else if( searchMode == SearchMode.or ) 
     381                                return [] 
     382                } 
     383 
     384                return entities.findAll { entity -> 
     385                        if( searchMode == SearchMode.and ) { 
     386                                for( criterion in criteria ) { 
     387                                        if( !check( entity, criterion ) ) { 
     388                                                return false; 
     389                                        } 
     390                                } 
     391                                return true; 
     392                        } else if( searchMode == SearchMode.or ) { 
     393                                for( criterion in criteria ) { 
     394                                        if( check( entity, criterion ) ) { 
     395                                                return true; 
     396                                        } 
     397                                } 
     398                                return false; 
     399                        } 
     400                } 
     401        } 
     402                 
    376403        /** 
    377404         * Filters the given list of studies on the study criteria 
     
    460487                return filterOnTemplateEntityCriteria(studies, entity, valueCallback( entity ) ) 
    461488        } 
     489         
     490        /******************************************************************** 
     491         *  
     492         * Methods for filtering object lists on module criteria 
     493         *  
     494         ********************************************************************/ 
    462495 
    463496        /** 
     
    690723        } 
    691724 
     725         
     726        /************************************************************************ 
     727         *  
     728         * Getters and setters 
     729         *  
     730         ************************************************************************/ 
     731         
     732        /** 
     733        * Returns a list of Criteria 
     734        */ 
     735   public List getCriteria() { return criteria; } 
     736 
     737   /** 
     738        * Sets a new list of criteria 
     739        * @param c      List with criteria objects 
     740        */ 
     741   public void setCriteria( List c ) { criteria = c; } 
     742 
     743   /** 
     744        * Adds a criterion to this query 
     745        * @param c      Criterion 
     746        */ 
     747   public void addCriterion( Criterion c ) { 
     748           if( criteria ) 
     749                   criteria << c; 
     750           else 
     751                   criteria = [c]; 
     752   } 
     753 
     754   /** 
     755        * Retrieves the results found using this query. The result is empty is 
     756        * the query has not been executed yet. 
     757        */ 
     758   public List getResults() { return results; } 
     759 
     760   /** 
     761        * Returns the results found using this query, filtered by a list of ids. 
     762        * @param selectedIds    List with ids of the entities you want to return. 
     763        * @return       A list with only those results for which the id is in the selectedIds 
     764        */ 
     765   public List filterResults( List selectedIds ) { 
     766           if( !selectedIds || !results ) 
     767                   return results 
     768 
     769           return results.findAll { 
     770                   selectedIds.contains( it.id ) 
     771           } 
     772   } 
     773 
     774   /** 
     775        * Returns a list of fields for the results of this query. The fields returned are those 
     776        * fields that the query searched for. 
     777        */ 
     778   public Map getResultFields() { return resultFields; } 
     779         
    692780        public String toString() { 
    693781                return ( this.entity ? this.entity + " search" : "Search" ) + " " + this.id 
    694782        } 
     783         
     784        public boolean equals( Object o ) { 
     785                if( o == null ) 
     786                        return false 
     787                 
     788                if( !( o instanceof Search ) )   
     789                        return false 
     790                         
     791                Search s = (Search) o; 
     792                 
     793                return (        searchMode              == s.searchMode &&  
     794                                        entity                  == s.entity &&  
     795                                        criteria.size() == s.criteria.size() &&  
     796                                        s.criteria.containsAll( criteria ) &&  
     797                                        criteria.containsAll( s.criteria ) ); 
     798        } 
    695799} 
  • trunk/src/groovy/dbnp/query/StudySearch.groovy

    r1524 r1526  
    6565         */ 
    6666        @Override 
    67         void executeAnd() { 
     67        protected void executeAnd() { 
    6868                def studies = Study.list().findAll { it.canRead( this.user ) }; 
    6969 
    70                 // If no criteria are found, return all studies 
    71                 if( !criteria || criteria.size() == 0 ) { 
    72                         results = studies; 
    73                         return; 
    74                 } 
    75  
    76                 // Perform filters 
    77                 studies = filterOnStudyCriteria( studies ); 
    78                 studies = filterOnSubjectCriteria( studies ); 
    79                 studies = filterOnSampleCriteria( studies ); 
    80                 studies = filterOnEventCriteria( studies ); 
    81                 studies = filterOnSamplingEventCriteria( studies ); 
    82                 studies = filterOnAssayCriteria( studies ); 
    83  
    84                 studies = filterOnModuleCriteria( studies ); 
    85  
    86                 // Save matches 
    87                 results = studies; 
     70                executeAnd( studies ); 
    8871        } 
    8972 
     
    121104         */ 
    122105        @Override 
    123         void executeOr() { 
     106        protected void executeOr() { 
    124107                def allStudies = Study.list().findAll { it.canRead( this.user ) }; 
    125  
    126                 // If no criteria are found, return all studies 
    127                 if( !criteria || criteria.size() == 0 ) { 
    128                         results = allStudies; 
    129                         return; 
    130                 } 
    131  
    132                 // Perform filters 
    133                 def studies = [] 
    134                 studies = ( studies + filterOnStudyCriteria( allStudies - studies ) ).unique(); 
    135                 studies = ( studies + filterOnSubjectCriteria( allStudies - studies ) ).unique(); 
    136                 studies = ( studies + filterOnSampleCriteria( allStudies - studies ) ).unique(); 
    137                 studies = ( studies + filterOnEventCriteria( allStudies - studies ) ).unique(); 
    138                 studies = ( studies + filterOnSamplingEventCriteria( allStudies - studies ) ).unique(); 
    139                 studies = ( studies + filterOnAssayCriteria( allStudies - studies ) ).unique(); 
    140                  
    141                 studies = ( studies + filterOnModuleCriteria( allStudies - studies ) ).unique(); 
    142                  
    143                 // Save matches 
    144                 results = studies; 
     108                executeOr( allStudies ); 
    145109        } 
    146110 
  • trunk/web-app/css/advancedQuery.css

    r1524 r1526  
    11label { display: inline-block; zoom: 1; *display: inline; width: 110px; margin-top: 10px;  } 
    22 
    3 #searchForm { position: relative; border: 1px solid #666666; padding: 5px 10px; margin: 10px 0; } 
     3#searchForm { position: relative; margin: 10px 0; font-size: 11px; } 
     4#searchForm h3 { font-size: 13px; } 
     5#searchForm h3 .nummer { display: inline-block; zoom: 1; *display: inline; width: 25px; }  
    46 
    5 #searchForm ul#criteria { margin-left: 110px; padding-left: 0px; margin-top: -19px; list-style-type: none;  } 
    6 #searchForm ul#criteria li { margin: 2px 0; padding-left: 0; } 
     7#searchForm p { margin-left: 25px; } 
     8 
     9#searchForm ul#criteria { margin-left: 25px; padding-left: 0px; list-style-type: none;  } 
     10#searchForm ul#criteria li { margin: 2px 0; padding: 2px 0; } 
    711#searchForm ul#criteria li span,  
    812#searchForm ul#criteria li a { display: inline-block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-right: 5px; } 
    9 #searchForm ul#criteria li .entityfield { width: 180px; } 
     13#searchForm ul#criteria li .entityfield { width: 200px; } 
    1014#searchForm ul#criteria li .operator { width: 100px; } 
    1115#searchForm ul#criteria li .value { width: 240px; } 
     16#searchForm ul#criteria li .addButton { margin: 4px 0; } 
     17#searchForm ul#criteria li input, #searchForm ul#criteria li select { font-size: 11px; } 
    1218 
    13 #searchForm ul#criteria li.emptyList { color: #666; } 
    14 #searchForm ul#criteria li.emptyList:hover { cursor: default; } 
     19#searchForm ul#criteria li.titlerow { font-weight: bold; border-bottom: 1px solid #aaa; } 
    1520 
    16 #searchForm ul#criteria li:hover { cursor: pointer; } 
    17 #searchForm ul#criteria li:hover span { text-decoration: line-through; } 
    18  
    19 #input_criteria { display: block; float: right; width: 260px; border-left: 1px solid #666; padding: 10px; position: relative; height: 100%; } 
    20 #input_criteria h2 { margin-top: 2px; margin-bottom: 8px; font-weight: bold; } 
    21 #input_criteria label { width: 80px; margin-top: 8px; } 
    22 #input_criteria input.text, #input_criteria select { width: 165px; } 
    23 #input_criteria input.button {  margin-top: 8px; } 
    24 #input_criteria .explanation { font-size: 10px; } 
     21#searchMode { display: none; } 
    2522 
    2623.ui-menu-item .entity { color: #666; font-style: italic; } 
  • trunk/web-app/js/advancedQuery.js

    r1482 r1526  
    88        // By replacing it with javascript, users without javascript will still be able to use the select 
    99        $( '#queryFieldSelect' ).after( $( '<input type="text" class="text" id="queryFieldText">' )); 
    10         $( '#queryFieldText' ).after( $( '<input type="hidden" name="field" id="queryField"></span>' )); 
     10        $( '#queryFieldText' ).after( $( '<input type="hidden" name="criteria.0.entityfield" id="queryField"></span>' )); 
    1111        $( '#queryFieldSelect' ).remove(); 
    1212 
     
    4040 
    4141// Is used to keep track of a unique ID for all criteria. 
    42 var criteriumId = 0; 
     42// ID = 0 is used for the input fields, in order to have them sent as well 
     43// when the user clicks 'run query' 
     44var criteriumId = 1; 
    4345 
    4446/** 
    4547 * Adds a criteria to the list of search criteria  
    4648 */ 
    47 function addCriterium() { 
    48         var field_descriptor = $( '#input_criteria [name=field]' ).val(); 
    49         var value = $( '#input_criteria input[name=value]' ).val(); 
    50         var operator = $( '#input_criteria select[name=operator]' ).val(); 
     49function addCriterion() { 
     50        var field_descriptor = $( '#searchForm #queryField' ).val(); 
     51        var value = $( '#searchForm input#value' ).val(); 
     52        var operator = $( '#searchForm select#operator' ).val(); 
    5153         
    5254        // Show the title and a remove button 
    5355        showCriterium(field_descriptor, value, operator); 
    54         showHideNoCriteriaItem(); 
     56        toggleSearchMode(); 
    5557         
    5658        // Clear the input form 
    57         $( '#input_criteria #queryFieldText' ).val( '' ); 
    58         $( '#input_criteria [name=field]' ).val( '' ); 
    59         $( '#input_criteria select[name=operator]' ).val( 'equals' ); 
    60         $( '#input_criteria input[name=value]' ).val( '' ); 
    61 } 
    62  
    63 function showHideNoCriteriaItem() { 
    64         remainingCriteria = $( '#criteria' ).children().length - 1; // -1 because one element is the 'empty' item 
    65  
    66         if( remainingCriteria == 0 ) { 
    67                 // Show the 'none box' 
    68                 $('#criteria .emptyList').show(); 
    69                 $('.submitcriteria' ).attr( 'disabled', 'disabled' ); 
    70         } else { 
    71                 // Hide the 'none box' 
    72                 $('#criteria .emptyList').hide(); 
    73                 $('.submitcriteria' ).attr( 'disabled', '' ); 
    74         }        
     59        $( '#searchForm #queryFieldText' ).val( '' ); 
     60        $( '#searchForm #queryField' ).val( '' ); 
     61        $( '#searchForm select#operator' ).val( 'equals' ); 
     62        $( '#searchForm input#value' ).val( '' ); 
    7563} 
    7664 
     
    8068function removeCriterium(element) { 
    8169        element.remove(); 
    82         showHideNoCriteriaItem(); 
     70        toggleSearchMode(); 
    8371} 
     72 
     73function toggleSearchMode() { 
     74        if( $('#criteria' ).children( 'li' ) - 2 == 0 ) { 
     75                $( '#searchMode' ).hide(); 
     76        } else { 
     77                $( '#searchMode' ).show(); 
     78        } 
     79} 
     80 
    8481 
    8582/** 
     
    9895                valueSpan = createCriteriumElement( 'value', value ); 
    9996         
     97        var input = $( '<a href="#" onClick="return false;"><img src="../plugins/famfamfam-1.0.1/images/icons/delete.png" border="0"></a>' ); 
     98        input.bind( 'click', function() { 
     99                if( confirm( "Are you sure you want to remove this criterium?" ) ) { 
     100                        removeCriterium( $(this).closest( 'li' ) ); 
     101                        return false; 
     102                } 
     103        }); 
     104        var span = $( '<span></span>' ); 
     105        span.append( "\n" ).append( input ); 
     106         
    100107        // Increase the criteriumID to ensure a unique number every time 
    101108        criteriumId++; 
     
    103110        // Append them to a list item 
    104111        var li = $( '<li></li>' ); 
    105         li.append( fieldSpan ).append( operatorSpan ).append( valueSpan ); 
     112        li.append( fieldSpan ).append( "\n" ).append( operatorSpan ).append( "\n" ).append( valueSpan ).append( "\n" ).append( span ); 
    106113         
    107         li.bind( 'click', function() { 
    108                 if( confirm( "Are you sure you want to remove this criterium?" ) ) { 
    109                         removeCriterium( $(this) ); 
    110                         return false; 
    111                 } 
    112         }); 
    113114 
    114         $('#criteria').append(li); 
     115        $('#criteria .newCriterion').before(li); 
    115116} 
    116117