Ignore:
Timestamp:
Feb 7, 2011, 4:07:54 PM (10 years ago)
Author:
robert@…
Message:
  • Number of seconds for the rest controller to keep data in cache is now a configuration option
  • After searching, it is possible to choose which action to perform on the search results.
File:
1 edited

Legend:

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

    r1482 r1501  
    11package dbnp.query
     2
    23import dbnp.modules.*
    34import org.dbnp.gdt.*
     
    1516
    1617        def entitiesToSearchFor = [ 'Study': 'Studies', 'Sample': 'Samples']
    17        
     18
    1819        /**
    1920         * Shows search screen
     
    2526                        criteria = parseCriteria( params.criteria, false )
    2627                }
    27                 [entitiesToSearchFor: entitiesToSearchFor, searchableFields: getSearchableFields(), criteria: criteria]
     28                [searchModes: SearchMode.values(), entitiesToSearchFor: entitiesToSearchFor, searchableFields: getSearchableFields(), criteria: criteria]
    2829        }
    2930
     
    4748
    4849                // Create a search object and let it do the searching
    49                 Search search;
     50                Search search = determineSearch( params.entity );
    5051                String view = determineView( params.entity );
    51                 switch( params.entity ) {
    52                         case "Study":   search = new StudySearch();     break;
    53                         case "Sample":  search = new SampleSearch(); break;
    54 
    55                         // This exception will only be thrown if the entitiesToSearchFor contains more entities than
    56                         // mentioned in this switch structure.
    57                         default:                throw new Exception( "Can't search for entities of type " + params.entity );
    58                 }
     52
     53                // Choose between AND and OR search. Default is given by the Search class itself.
     54                switch( params.operator?.toString()?.toLowerCase() ) {
     55                        case "or":
     56                                search.searchMode = SearchMode.or;
     57                                break;
     58                        case "and":
     59                                search.searchMode = SearchMode.and;
     60                                break;
     61                }
     62
    5963                search.execute( parseCriteria( params.criteria ) );
    6064
    6165                // Save search in session
    6266                def queryId = saveSearch( search );
    63                 render( view: view, model: [search: search, queryId: queryId] );
     67                render( view: view, model: [search: search, queryId: queryId, actions: determineActions(search)] );
    6468        }
    6569
     
    6973         */
    7074        def discard = {
    71                 Integer queryId
    72                 try {
    73                         queryId = params.id as Integer
    74                 } catch( Exception e ) {
     75                def queryIds = params.list( 'id' );
     76                queryIds = queryIds.findAll { it.isInteger() }.collect { Integer.valueOf( it ) }
     77
     78                if( queryIds.size() == 0 ) {
    7579                        flash.error = "Incorrect search ID given to discard"
    7680                        redirect( action: "index" );
     
    7882                }
    7983
    80                 discardSearch( queryId );
    81                 flash.message = "Search has been discarded"
     84                queryIds.each { queryId ->
     85                        discardSearch( queryId );
     86                }
     87
     88                if( queryIds.size() > 1 ) {
     89                        flash.message = "Searches have been discarded"
     90                } else {
     91                        flash.message = "Search has been discarded"
     92                }
    8293                redirect( action: "list" );
    8394        }
     
    8899         */
    89100        def show = {
    90                 Integer queryId
    91                 try {
    92                         queryId = params.id as Integer
    93                 } catch( Exception e ) {
     101                def queryId = params.int( 'id' );
     102
     103                if( !queryId ) {
    94104                        flash.error = "Incorrect search ID given to show"
    95105                        redirect( action: "index" );
     
    107117                // Determine which view to show
    108118                def view = determineView( s.entity );
    109                 render( view: view, model: [search: s, queryId: queryId] );
    110         }
    111 
     119                render( view: view, model: [search: s, queryId: queryId, actions: determineActions(s)] );
     120        }
     121
     122        /**
     123         * Performs an action on specific searchResults
     124         * @param       queryId         queryId of the search to show
     125         * @param       id                      list with the ids of the results to perform the action on
     126         * @param       actionName      Name of the action to perform
     127         */
     128        def performAction = {
     129                def queryId = params.int( 'queryId' );
     130                def selectedIds = params.list( 'id' ).findAll { it.isLong() }.collect { Long.parseLong(it) }
     131                def actionName = params.actionName;
     132                def moduleName = params.moduleName;
     133
     134                if( !queryId ) {
     135                        flash.error = "Incorrect search ID given to show"
     136                        redirect( action: "index" );
     137                        return
     138                }
     139               
     140                // Retrieve the search from session
     141                Search s = retrieveSearch( queryId );
     142                if( !s ) {
     143                        flash.message = "Specified search could not be found"
     144                        redirect( action: "list" );
     145                        return;
     146                }
     147
     148                // Determine the possible actions
     149                def actions = determineActions(s, selectedIds );
     150
     151                // Find the right action to perform
     152                def redirectUrl;
     153                for( action in actions ) {
     154                        if( action.module == moduleName && action.name == actionName ) {
     155                                redirectUrl = action.url;
     156                                break;
     157                        }
     158                }
     159               
     160                if( !redirectUrl ) {
     161                        flash.error = "No valid action is given to perform";
     162                        redirect( action: "show", id: queryId );
     163                        return;
     164                }
     165               
     166                redirect( url: redirectUrl );
     167        }
     168       
    112169        /**
    113170         * Shows a list of searches that have been saved in session
     
    124181                [searches: searches]
    125182        }
    126        
     183
    127184        /**
    128185         * Shows a search screen where the user can search within the results of another search
     
    130187         */
    131188        def searchIn = {
    132                 Integer queryId
    133                 try {
    134                         queryId = params.id as Integer
    135                 } catch( Exception e ) {
     189                def queryIds = params.list( 'id' );
     190                queryIds = queryIds.findAll { it.isInteger() }.collect { Integer.valueOf( it ) }
     191
     192                if( queryIds.size() == 0 ) {
    136193                        flash.error = "Incorrect search ID given to show"
    137194                        redirect( action: "index" );
     
    139196                }
    140197
    141                 // Retrieve the search from session
    142                 Search s = retrieveSearch( queryId );
    143                 if( !s ) {
    144                         flash.message = "Specified search could not be found"
     198                // Retrieve the searches from session
     199                def params = [:]
     200                queryIds.eachWithIndex { queryId, idx ->
     201                        Search s = retrieveSearch( queryId );
     202                        if( !s ) {
     203                                flash.message = "Specified search " + queryId + " could not be found"
     204                                return;
     205                        } else {
     206                                params[ "criteria." + idx + ".entityfield" ] = s.entity;
     207                                params[ "criteria." + idx + ".operator" ] = "in";
     208                                params[ "criteria." + idx + ".value" ] = queryId;
     209                        }
     210                }
     211
     212                redirect( action: "index", params: params)
     213        }
     214
     215        /**
     216         * Combines the results of multiple searches
     217         * @param       id      queryIds of the searches to combine
     218         */
     219        def combine = {
     220                def queryIds = params.list( 'id' );
     221                queryIds = queryIds.findAll { it.isInteger() }.collect { Integer.valueOf( it ) }
     222
     223                if( queryIds.size() == 0 ) {
     224                        flash.error = "Incorrect search ID given to combine"
    145225                        redirect( action: "index" );
     226                        return
     227                }
     228
     229                // First determine whether the types match
     230                def searches = [];
     231                def type = "";
     232                flash.error = "";
     233                queryIds.eachWithIndex { queryId, idx ->
     234                        Search s = retrieveSearch( queryId );
     235                        if( !s ) {
     236                                return;
     237                        }
     238
     239                        if( type ) {
     240                                if( type != s.entity ) {
     241                                        flash.error = type + " and " + s.entity.toLowerCase() + " queries can't be combined. Selected queries of one type.";
     242                                        return
     243                                }
     244                        } else {
     245                                type = s.entity
     246                        }
     247                }
     248
     249                if( flash.error ) {
     250                        redirect( action: "list" );
    146251                        return;
    147252                }
    148253
    149                 redirect( action: "index", params: [ "criteria.0.entityfield": s.entity, "criteria.0.operator": "in", "criteria.0.value": queryId ])
     254                if( !type ) {
     255                        flash.error = "No correct query ids were given."
     256                        redirect( action: "list" );
     257                        return;
     258                }
     259
     260                // Retrieve the searches from session
     261                Search combined = determineSearch( type );
     262                combined.searchMode = SearchMode.or;
     263
     264                queryIds.eachWithIndex { queryId, idx ->
     265                        Search s = retrieveSearch( queryId );
     266                        if( s ) {
     267                                combined.addCriterion( new Criterion( entity: type, field: null, operator: Operator.insearch, value: s ) );
     268                        }
     269                }
     270
     271                // Execute search to combine the results
     272                combined.execute();
     273
     274                def queryId = saveSearch( combined );
     275                redirect( action: "show", id: queryId );
    150276        }
    151277
     
    155281                        case "Sample":  return "sampleresults"; break;
    156282                        default:                return "results"; break;
     283                }
     284        }
     285
     286        /**
     287         * Returns the search object used for searching
     288         */
     289        protected Search determineSearch( String entity ) {
     290                switch( entity ) {
     291                        case "Study":   return new StudySearch();
     292                        case "Sample":  return new SampleSearch();
     293
     294                        // This exception will only be thrown if the entitiesToSearchFor contains more entities than
     295                        // mentioned in this switch structure.
     296                        default:                throw new Exception( "Can't search for entities of type " + entity );
    157297                }
    158298        }
     
    230370                        if( c.key ==~ /[0-9]+/ ) {
    231371                                def formCriterion = c.value;
    232                                
     372
    233373                                Criterion criterion = new Criterion();
    234374
     
    251391                                        continue;
    252392                                }
    253                                
     393
    254394                                // Special case of the 'in' operator
    255395                                if( criterion.operator == Operator.insearch ) {
     
    258398                                                s = retrieveSearch( Integer.parseInt( formCriterion.value ) );
    259399                                        } catch( Exception e ) {}
    260                                        
     400
    261401                                        if( !s ) {
    262402                                                flash.error += "Can't search within previous query: query not found";
    263403                                                continue;
    264404                                        }
    265                                        
     405
    266406                                        if( parseSearchIds ) {
    267407                                                criterion.value = s
     
    273413                                        criterion.value = formCriterion.value;
    274414                                }
    275                                
     415
    276416                                list << criterion;
    277417                        }
     
    332472                // First check whether a search with the same criteria is already present
    333473                def previousSearch = retrieveSearchByCriteria( s.getCriteria() );
    334                
     474
    335475                def id
    336476                if( previousSearch ) {
     
    340480                        id = ( session.queries*.key.max() ?: 0 ) + 1;
    341481                }
    342                
     482
    343483                s.id = id;
    344484                session.queries[ id ] = s;
    345485
    346                 println "On saveSearch: " + session.queries;
    347486                return id;
    348487        }
     
    356495                if( !session.queries )
    357496                        return null
    358                
     497
    359498                if( !criteria )
    360499                        return null
    361                        
     500
    362501                for( query in session.queries ) {
    363502                        def key = query.key;
     
    385524                        return null;
    386525
    387                 println "On retrieveSearch: " + session.queries;
    388526                return (Search) session.queries[ id ]
    389527        }
     
    402540                session.queries.remove( id );
    403541
    404                 println "On discardSearch: " + session.queries;
    405542                if( !( sessionSearch instanceof Search ) )
    406543                        return null;
     
    419556                return session.queries*.value.toList()
    420557        }
     558
     559        /**
     560         * Determine a list of actions that can be performed on specific entities
     561         * @param entity                Name of the entity that the actions could be performed on
     562         * @param selectedIds   List with ids of the selected items to perform an action on
     563         * @return
     564         */
     565        protected List determineActions( Search s, def selectedIds = null ) {
     566                return gscfActions( s, selectedIds ) + moduleActions( s, selectedIds );
     567        }
     568
     569        /**
     570         * Determine a list of actions that can be performed on specific entities by GSCF
     571         * @param entity        Name of the entity that the actions could be performed on
     572         * @param selectedIds   List with ids of the selected items to perform an action on
     573         */
     574        protected List gscfActions(Search s, def selectedIds = null) {
     575                switch(s.entity) {
     576                        case "Study":
     577                                def exportParams = [:]
     578                                s.filterResults(selectedIds).each {
     579                                        exportParams[ it.code ] = it.id;
     580                                }
     581                                return [[
     582                                                module: "gscf",
     583                                                name:"simpletox",
     584                                                description: "Export as SimpleTox",
     585                                                url: createLink( controller: "exporter", action: "export", params: exportParams )
     586                                        ]]
     587                        case "Sample":
     588                                return []
     589                        default:
     590                                return [];
     591                }
     592        }
     593
     594        /**
     595         * Determine a list of actions that can be performed on specific entities by other modules
     596         * @param entity        Name of the entity that the actions could be performed on
     597         */
     598        protected List moduleActions(Search s, def selectedIds = null) {
     599                def actions = []
     600
     601                if( !s.getResults() || s.getResults().size() == 0 )
     602                        return []
     603
     604                // Loop through all modules and check which actions can be performed on the
     605                AssayModule.list().each { module ->
     606                        // Remove 'module' from module name
     607                        def moduleName = module.name.replace( 'module', '' ).trim()
     608                        try {
     609                                def callUrl = module.url + "/rest/getPossibleActions?entity=" + s.entity
     610                                def json = moduleCommunicationService.callModuleRestMethodJSON( module.url, callUrl );
     611
     612                                // Check whether the entity is present in the return value
     613                                if( json[ s.entity ] ) {
     614                                        json[ s.entity ].each { action ->
     615                                                def url = module.url + "/action/" + action.name
     616                                                url += "?entity=" + s.entity
     617                                                url += "&" + s.filterResults(selectedIds).collect { "tokens=" + it.giveUUID() }.join( "&" )
     618                                                actions << [
     619                                                                        module: moduleName,
     620                                                                        name: action.name,
     621                                                                        description: action.description + " (" + moduleName + ")",
     622                                                                        url: url
     623                                                                ];
     624                                        }
     625                                }
     626                        } catch( Exception e ) {
     627                                // Exception is thrown when the call to the module fails. No problems though.
     628                                log.error "Error while fetching possible actions from " + module.name + ": " + e.getMessage()
     629                        }
     630                }
     631
     632                return actions;
     633        }
     634
    421635}
Note: See TracChangeset for help on using the changeset viewer.