source: main/waeup.kofa/trunk/src/waeup/kofa/doctests/catalog.txt @ 14222

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

Simplify headlines in doctests. Remove some API documentation.

File size: 5.9 KB
Line 
1Cataloging Support
2******************
3
4.. module:: waeup.kofa.catalog
5
6Components that support cataloging and searching objects inside a
7Kofa site.
8
9.. :doctest:
10.. :layer: waeup.kofa.testing.KofaUnitTestLayer
11
12Getting a general query object
13==============================
14
15We can get a KofaQuery object by asking for an unnamed global utility
16implementing `hurry.query.interfaces.IQuery`:
17
18    >>> from hurry.query.interfaces import IQuery
19    >>> from zope.component import getUtility
20    >>> q = getUtility(IQuery)
21    >>> q
22    <waeup.kofa.catalog.KofaQuery object at 0x...>
23
24This query can get 'subqueries' and delivers the objects found or
25their ids. To show this we have to setup a catalog with some entries.
26
27
28Setting up a catalog and feeding it
29===================================
30
31    >>> from zope.catalog.interfaces import ICatalog
32    >>> from zope.catalog.catalog import Catalog
33    >>> mycat = Catalog()
34
35We register this catalog with the component architechture as a utility
36named 'mycatalog':
37
38    >>> from zope.component import provideUtility
39    >>> provideUtility(mycat, ICatalog, 'mycatalog')
40
41We setup a special content type whose instances we will catalog later:
42
43    >>> from zope.interface import Interface, Attribute, implements
44    >>> from zope.container.contained import Contained
45    >>> class IMammoth(Interface):
46    ...   name = Attribute('name')
47    ...   age = Attribute('age')
48
49    >>> class Mammoth(Contained):
50    ...   implements(IMammoth)
51    ...   def __init__(self, name, age):
52    ...     self.name = name
53    ...     self.age = age
54    ...   def __cmp__(self, other):
55    ...     return cmp(self.name, other.name)
56
57By including the __cmp__ method we make sure search results can be
58stably sorted.
59
60We also setup a `zope.intid.interfaces.IIntIds` utility. This is not
61necessary for plain catalogs, but when we want to use KofaQuery (or
62`hurry.query.query.Query` objects), as to get a unique mapping from
63objects (stored in ZODB) to integer numbers (stored in catalogs),
64these query objects lookup a global IIntIds utiliy:
65
66    >>> from zope import interface
67    >>> import zope.intid.interfaces
68    >>> class DummyIntId(object):
69    ...     interface.implements(zope.intid.interfaces.IIntIds)
70    ...     MARKER = '__dummy_int_id__'
71    ...     def __init__(self):
72    ...         self.counter = 0
73    ...         self.data = {}
74    ...     def register(self, obj):
75    ...         intid = getattr(obj, self.MARKER, None)
76    ...         if intid is None:
77    ...             setattr(obj, self.MARKER, self.counter)
78    ...             self.data[self.counter] = obj
79    ...             intid = self.counter
80    ...             self.counter += 1
81    ...         return intid
82    ...     def getObject(self, intid):
83    ...         return self.data[intid]
84    ...     def __iter__(self):
85    ...         return iter(self.data)
86    >>> intid = DummyIntId()
87    >>> from zope.component import provideUtility
88    >>> provideUtility(intid, zope.intid.interfaces.IIntIds)
89
90Now we can catalog some mammoths. Here we create a herd and catalog
91each item of it:
92
93    >>> from zope.catalog.field import FieldIndex
94    >>> mycat['mammoth_name'] = FieldIndex('name', IMammoth)
95    >>> mycat['mammoth_age'] = FieldIndex('age', IMammoth)
96
97    >>> herd = [
98    ...   Mammoth(name='Fred', age=33),
99    ...   Mammoth(name='Hank', age=30),
100    ...   Mammoth(name='Wilma', age=28),
101    ... ]
102
103    >>> for mammoth in herd:
104    ...   mycat.index_doc(intid.register(mammoth), mammoth)
105
106
107Searching for result sets
108=========================
109
110Finally we can perform queries:
111
112    >>> from hurry.query import Eq
113    >>> from zope.component import getUtility
114    >>> subquery1 = Eq(('mycatalog', 'mammoth_name'), 'Fred')
115
116The latter means: search for objects whose name is ``'Fred'`` in the
117``mammoth_name`` index of a catalog registered as a utility named
118``mycatalog``.
119
120    >>> from hurry.query import Between
121    >>> subquery2 = Between(('mycatalog', 'mammoth_age'), 30, 33)
122
123This means: ask for objects cataloged in an index named 'mammoth_age',
124whose cataloged value is between 30 and 33 (including this values).
125
126    >>> r1 = q.apply(subquery2)
127    >>> r1
128    IFSet([0, 1])
129
130Using ``apply()`` above, we get a set of values stored in an
131``IFBTree``:
132
133    >>> type(r1)
134    <type 'BTrees.IFBTree.IFSet'>
135
136``IFBTree`` objects implement a rather efficient integer to float
137mapping where also integers are allowed as values. For each object
138found (i.e. mammoths whose age is between 30 and 33), we get the
139number of its entry.
140
141To get the real object, we can use intids here, because we setup an
142appropriate IIntIds utility before:
143
144    >>> [intid.getObject(x).name for x in r1]
145    ['Fred', 'Hank']
146
147We can (and should) also use the `searchResults()` method explained
148below to do that.
149
150Retrieving BTree sets can, however, make sense, if you want to know
151only the number of results for a particular query or whether there are
152results at all in a more efficient way:
153
154    >>> len(r1)
155    2
156
157Searching for objects
158=====================
159
160Very often we don't want to know the catalog-internal 'ids' of
161searched objects but the objects themselves.
162
163This can be done by using the ``searchResults`` method of
164``KofaQuery``:
165
166    >>> r2 = q.searchResults(subquery1)
167    >>> r2
168    <zope.catalog.catalog.ResultSet instance at 0x...>
169
170    >>> list(r2)
171    [<Mammoth object at 0x...>]
172
173We got one result item, we can immediately ask for further infos. To
174access a result item by its index number, we have to turn the
175ResultSet into an ordinary list before:
176
177    >>> entry = list(r2)[0]
178    >>> entry.name, entry.age
179    ('Fred', 33)
180
181We can also use ``subquery2`` as above:
182
183    >>> r3 = q.searchResults(subquery2)
184    >>> [(x.name, x.age) for x in r3]
185    [('Fred', 33), ('Hank', 30)]
186
187or use both queries at once:
188
189    >>> r4 = q.searchResults(subquery1 & subquery2)
190    >>> [(x.name, x.age) for x in r4]
191    [('Fred', 33)]
192
193which will give us, of course, the same result set as with subquery1.
Note: See TracBrowser for help on using the repository browser.