source: main/waeup.kofa/trunk/src/waeup/kofa/catalog.py @ 17808

Last change on this file since 17808 was 12951, checked in by Henrik Bettermann, 10 years ago

Simplify headlines in doctests. Remove some API documentation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.9 KB
RevLine 
[7193]1## $Id: catalog.py 12951 2015-05-15 08:56:17Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
[5090]18"""Components to help cataloging and searching objects.
19"""
[3521]20import grok
[5090]21from hurry.query.interfaces import IQuery
22from hurry.query.query import Query
23from zope.catalog.catalog import ResultSet
[9767]24from zope.catalog.interfaces import ICatalog
25from zope.component import getUtility, queryUtility
26from zope.interface import implementer
[5090]27from zope.intid.interfaces import IIntIds
[9767]28from waeup.kofa.interfaces import (
29    IQueryResultItem, IFilteredQuery, IFilteredCatalogQuery)
[3521]30
[6447]31# not yet used
[9767]32@implementer(IQuery)
[7819]33class KofaQuery(Query):
[12951]34    """A `hurry.query.query.Query` compatible query that also supports
35    retrival of plain ``Bree`` result sets as used inside a catalog.
36
37    Like `hurry.query.query.Query` objects, `KofaQuery` is some kind
38    of a meta query or 'compound query' that can give the cataloged
39    objects (or their int ids) matching one or more 'subqueries'.
40
41    This way you can search for objects (or their int ids) that match
42    several criteria at the same time. See ``examples`` section below.
43
44    A singleton instance of this class is also available as global
45    utility.
46
47    A hurry.query-like query that supports also ``apply``.
[6207]48    """
49    def apply(self, query):
[12951]50        """Get the list of int ids (a `BTree` result set) for objects
51        determined by ``query``.
52
53        The list of int ids is less expensive to compute than the
54        complete search results and sufficient, for instance, when you
55        only need the number of objects that match a query and not the
56        objects themselves.
[6207]57        """
58        return query.apply()
[5090]59
[6207]60    def searchResults(self, query):
61        """Get a set of ZODB objects conforming to a query.
62        """
63        results = self.apply(query)
64        if results is not None:
65            uidutil = getUtility(IIntIds)
66            results = ResultSet(results, uidutil)
67        return results
[5090]68
[7819]69grok.global_utility(KofaQuery)
[5090]70
[6447]71# not yet used
[9767]72@implementer(IQueryResultItem)
[4789]73class QueryResultItem(object):
[6207]74    url = None
75    title = None
76    description = None
[6116]77
[6207]78    def __init__(self, context, view):
79        self.context = context
80        self.url = view.url(context)
81        self.title = context.title
82        self.description = ''
[9767]83
84@implementer(IFilteredQuery)
85class FilteredQueryBase(object):
86    """A filter to find objects that match certain parameters.
[9773]87
88    Parameters are passed to constructor as keyword arguments. The
89    real data retrieval then happens when `query()` is called.
90
91    The `defaults` attribute, a dict, can set certain default values
92    for parameters that are used if the constructor is called without
93    any parameters.
[9767]94    """
95    defaults = dict()
96
97    def __init__(self, **kw):
98        self._kw = dict(self.defaults)
99        self._kw.update(kw)
100        return
101
102    def query(self, context=None):
103        err_msg = 'class %s does not implement the query() method.' % (
104            self.__class__.__name__, )
105        raise NotImplementedError(err_msg)
106
107@implementer(IFilteredCatalogQuery)
108class FilteredCatalogQueryBase(FilteredQueryBase):
[9773]109    """Base for filtered queries based on catalog lookups.
110
111    This type of query asks a catalog to find objects.
112
113    You would normally use this type of query like this:
114
115      >>> query = FilteredCatalogQueryBase(name='bob')
116      >>> objects = query.query()
117
118    The name of the catalog to use can be set via `cat_name`
119    attribute.
120
121    Looked up are all objects that match keywords passed to
122    constructor where the keyword names must match a certain index of
123    the chosen catalog. So, if some catalog has indexes `name` and
124    `age`, then keywords `name='bob', age='12'` would search for all
125    objects with name ``bob`` and age ``12``.
126
127    This query supports single values (exact matches) and ranges of
128    values passed in via ``(min_value, max_value)`` tuples. So,
129    constructor keyword args `name=('a', 'd')` would find objects with
130    name ``alice``, ``bob``, ``d``, but not ``donald``, ``john``, or
131    ``zak``.
132    """
[9767]133    cat_name = None
134
135    def query_catalog(self, catalog):
[9773]136        """Search ``catalog``.
137
138        Use `catalog`, some ``Catalog`` instance, to search objects
139        denoted by constructor keywords.
140        """
[9767]141        query = dict()
142        for idx_name, value in self._kw.items():
[9845]143            if idx_name == 'catalog':
[9843]144                continue
[11483]145            if value is not None:
146                if 'session' in idx_name or 'level' in idx_name:
147                    value = int(value)
148                if idx_name in ('level', 'current_level'):
149                    value = int(value)
150                    if value not in (10, 999):
151                        value = (value, value + 90)
[9767]152            if not isinstance(value, tuple):
153                value = (value, value)
154            query[idx_name] = value
155        result = catalog.searchResults(**query)
156        return result
157
158    def query(self):
[9773]159        """Perform a query with parameters passed to constructor.
160
161        Returns some iterable, normally a list or a catalog result
162        set.
163        """
[9767]164        catalog = queryUtility(
165            ICatalog, name=self.cat_name, default=None)
166        if catalog is None:
167            return []
168        return self.query_catalog(catalog)
Note: See TracBrowser for help on using the repository browser.