[ckan-changes] commit/ckan: John Glover: [search] Move resource search function to logic layer

Bitbucket commits-noreply at bitbucket.org
Tue Sep 20 14:49:57 UTC 2011


1 new changeset in ckan:

http://bitbucket.org/okfn/ckan/changeset/1cecc34f9055/
changeset:   1cecc34f9055
branch:      feature-1302-resource-tag-search
user:        John Glover
date:        2011-09-20 16:49:18
summary:     [search] Move resource search function to logic layer
affected #:  3 files (-1 bytes)

--- a/ckan/lib/search/query.py	Tue Sep 20 12:07:57 2011 +0100
+++ b/ckan/lib/search/query.py	Tue Sep 20 15:49:18 2011 +0100
@@ -4,6 +4,7 @@
 from paste.util.multidict import MultiDict 
 from paste.deploy.converters import asbool
 from ckan import model
+from ckan.logic import get_action
 from common import make_connection, SearchError
 import logging
 log = logging.getLogger(__name__)
@@ -219,7 +220,7 @@
 
 
 class TagSearchQuery(SearchQuery):
-    """Search for tags in plain SQL."""
+    """Search for tags."""
     def _run(self):
         q = model.Session.query(model.Tag)
         q = q.distinct().join(model.Tag.package_tags)
@@ -235,38 +236,29 @@
 
 
 class ResourceSearchQuery(SearchQuery):
-    """ Search for resources in plain SQL. """
-    def _run(self):
-        q = model.Session.query(model.Resource) # TODO authz
-        if self.query.terms:
-            raise SearchError('Only field specific terms allowed in resource search.')
-        self.options.ref_entity_with_attr = 'id' # has no name
-        resource_fields = model.Resource.get_columns()
-        for field, terms in self.query.fields.items():
-            if isinstance(terms, basestring):
-                terms = terms.split()
-            if field not in resource_fields:
-                raise SearchError('Field "%s" not recognised in Resource search.' % field)
-            for term in terms:
-                model_attr = getattr(model.Resource, field)
-                if field == 'hash':                
-                    q = q.filter(model_attr.ilike(unicode(term) + '%'))
-                elif field in model.Resource.get_extra_columns():
-                    model_attr = getattr(model.Resource, 'extras')
+    """Search for resources."""
+    def run(self, query=None, terms=[], fields={}, facet_by=[], options=None, **kwargs):
+        if options is None:
+            options = QueryOptions(**kwargs) 
+        else:
+            options.update(kwargs)
 
-                    like = or_(
-                        model_attr.ilike(u'''%%"%s": "%%%s%%",%%''' % (field, term)),
-                        model_attr.ilike(u'''%%"%s": "%%%s%%"}''' % (field, term))
-                    )
-                    q = q.filter(like)
-                else:
-                    q = q.filter(model_attr.ilike('%' + unicode(term) + '%'))
-        
-        order_by = self.options.order_by
-        if order_by is not None:
-            if hasattr(model.Resource, order_by):
-                q = q.order_by(getattr(model.Resource, order_by))
-        self._db_query(q)
+        context = {'model':model, 'session': model.Session}
+        data_dict = {
+            'fields': fields,
+            'offset': options.get('offset'),
+            'limit': options.get('limit'),
+            'order_by': options.get('order_by')
+        }
+        results = get_action('resource_search')(context, data_dict)
+
+        # if options.all_fields is set, return a dict
+        # if not, return a list of resource IDs
+        if options.all_fields:
+           results['results'] = [r.as_dict() for r in results['results']]
+        else:
+            results['results'] = [r.id for r in results['results']]
+        return results
 
 
 class PackageSearchQuery(SearchQuery):


--- a/ckan/logic/action/get.py	Tue Sep 20 12:07:57 2011 +0100
+++ b/ckan/logic/action/get.py	Tue Sep 20 15:49:18 2011 +0100
@@ -21,7 +21,7 @@
                                                 group_to_api2,
                                                 tag_to_api1,
                                                 tag_to_api2)
-from ckan.lib.search import query_for
+from ckan.lib.search import query_for, SearchError
 
 def site_read(context,data_dict=None):
     check_access('site_read',context,data_dict)
@@ -625,3 +625,54 @@
         package_dict['isopen'] = False
 
     return package_dict
+
+def resource_search(context, data_dict):
+    model = context['model']
+    session = context['session']
+
+    fields = data_dict['fields']
+    order_by = data_dict.get('order_by')
+    offset = data_dict.get('offset')
+    limit = data_dict.get('limit')
+
+    # TODO: should we check for user authentication first?
+    q = model.Session.query(model.Resource)
+    resource_fields = model.Resource.get_columns()
+
+    for field, terms in fields.items():
+        if isinstance(terms, basestring):
+            terms = terms.split()
+        if field not in resource_fields:
+            raise SearchError('Field "%s" not recognised in Resource search.' % field)
+        for term in terms:
+            model_attr = getattr(model.Resource, field)
+            if field == 'hash':                
+                q = q.filter(model_attr.ilike(unicode(term) + '%'))
+            elif field in model.Resource.get_extra_columns():
+                model_attr = getattr(model.Resource, 'extras')
+
+                like = or_(
+                    model_attr.ilike(u'''%%"%s": "%%%s%%",%%''' % (field, term)),
+                    model_attr.ilike(u'''%%"%s": "%%%s%%"}''' % (field, term))
+                )
+                q = q.filter(like)
+            else:
+                q = q.filter(model_attr.ilike('%' + unicode(term) + '%'))
+    
+    if order_by is not None:
+        if hasattr(model.Resource, order_by):
+            q = q.order_by(getattr(model.Resource, order_by))
+
+    count = q.count()
+    q = q.offset(offset)
+    q = q.limit(limit)
+    
+    results = []
+    for result in q:
+        if isinstance(result, tuple) and isinstance(result[0], model.DomainObject):
+            # This is the case for order_by rank due to the add_column.
+            results.append(result[0])
+        else:
+            results.append(result)
+
+    return {'count': count, 'results': results}


--- a/ckan/tests/lib/test_resource_search.py	Tue Sep 20 12:07:57 2011 +0100
+++ b/ckan/tests/lib/test_resource_search.py	Tue Sep 20 15:49:18 2011 +0100
@@ -148,7 +148,7 @@
         resources = result['results']
         count = result['count']
         assert len(resources) == 2, resources
-        assert count == all_resource_count
+        assert count == all_resource_count, (count, all_resource_count)
         assert resources == all_resources[:2], '%r, %r' % (resources, all_resources)
 
         # offset
@@ -182,5 +182,3 @@
         # can't be searched
         fields = {'size_extra':'100'}
         assert_raises(search.SearchError, search.query_for(model.Resource).run, fields=fields)
-
-

Repository URL: https://bitbucket.org/okfn/ckan/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.




More information about the ckan-changes mailing list