[Zope-Checkins] CVS: Zope2 - FieldIndex.py:1.1.2.5
andreas@serenade.digicool.com
andreas@serenade.digicool.com
Tue, 22 May 2001 12:35:08 -0400
Update of /cvs-repository/Zope2/lib/python/Products/PluginIndexes/FieldIndex
In directory serenade:/tmp/cvs-serv18976/FieldIndex
Modified Files:
Tag: ajung-dropin-registry
FieldIndex.py
Log Message:
removed stupid code replication. FieldIndex now subclasses
UnIndex (same as KeywordIndex)
--- Updated File FieldIndex.py in package Zope2 --
--- FieldIndex.py 2001/05/21 20:23:49 1.1.2.4
+++ FieldIndex.py 2001/05/22 16:35:07 1.1.2.5
@@ -101,6 +101,7 @@
import BTrees.Length
from Products.PluginIndexes import PluggableIndex
+from Products.PluginIndexes.common.UnIndex import UnIndex
from Globals import Persistent, DTMLFile
from Acquisition import Implicit
@@ -112,7 +113,7 @@
_marker = []
-class FieldIndex(PluggableIndex.PluggableIndex, Persistent,
+class FieldIndex(UnIndex,PluggableIndex.PluggableIndex, Persistent,
Implicit, SimpleItem):
"""Field Indexes"""
@@ -123,363 +124,6 @@
manage_options= (
SimpleItem.manage_options
)
-
-
- def __init__(self, id, ignore_ex=None, call_methods=None):
- """Create an unindex
-
- UnIndexes are indexes that contain two index components, the
- forward index (like plain index objects) and an inverted
- index. The inverted index is so that objects can be unindexed
- even when the old value of the object is not known.
-
- e.g.
-
- self._index = {datum:[documentId1, documentId2]}
- self._unindex = {documentId:datum}
-
- If any item in self._index has a length-one value, the value is an
- integer, and not a set. There are special cases in the code to deal
- with this.
-
- The arguments are:
-
- 'id' -- the name of the item attribute to index. This is
- either an attribute name or a record key.
-
- 'ignore_ex' -- should be set to true if you want the index
- to ignore exceptions raised while indexing instead of
- propagating them.
-
- 'call_methods' -- should be set to true if you want the index
- to call the attribute 'id' (note: 'id' should be callable!)
- You will also need to pass in an object in the index and
- uninded methods for this to work.
-
- """
- self.id = id
- self.ignore_ex=ignore_ex # currently unimplimented
- self.call_methods=call_methods
-
- self.__len__=BTrees.Length.Length() # see __len__ method docstring
- self.clear()
-
- def clear(self):
- # inplace opportunistic conversion from old-style to new style BTrees
- try: self.__len__.set(0)
- except AttributeError: self.__len__=BTrees.Length.Length()
- self._index = OOBTree()
- self._unindex = IOBTree()
-
- def _convertBTrees(self, threshold=200):
- if type(self._index) is OOBTree: return
-
- from BTrees.convert import convert
-
- _index=self._index
- self._index=OOBTree()
-
- def convertSet(s,
- IITreeSet=IITreeSet, IntType=type(0),
- type=type, len=len,
- doneTypes = (IntType, IITreeSet)):
-
- if type(s) in doneTypes: return s
-
- if len(s) == 1:
- try: return s[0] # convert to int
- except: pass # This is just an optimization.
-
- return IITreeSet(s)
-
- convert(_index, self._index, threshold, convertSet)
-
- _unindex=self._unindex
- self._unindex=IOBTree()
- convert(_unindex, self._unindex, threshold)
-
- self.__len__=BTrees.Length.Length(len(_index))
-
-
- def numObjects(self):
- """ return number of indexed objects """
- return len(self._index)
-
- def __nonzero__(self):
- return not not self._unindex
-
- def __len__(self):
- """Return the number of objects indexed.
-
- This method is only called for indexes which have "old" BTrees,
- and the *only* reason that UnIndexes maintain a __len__ is for
- the searching code in the catalog during sorting.
- """
- return len(self._unindex)
-
- def histogram(self):
- """Return a mapping which provides a histogram of the number of
- elements found at each point in the index."""
-
- histogram = {}
- for item in self._index.items():
- if type(item) is IntType:
- entry = 1 # "set" length is 1
- else:
- key, value = item
- entry = len(value)
- histogram[entry] = histogram.get(entry, 0) + 1
-
- return histogram
-
-
- def referencedObjects(self):
- """Generate a list of IDs for which we have referenced objects."""
- return self._unindex.keys()
-
-
- def getEntryForObject(self, documentId, default=_marker):
- """Takes a document ID and returns all the information we have
- on that specific object."""
- if default is _marker:
- return self._unindex.get(documentId)
- else:
- return self._unindex.get(documentId, default)
-
-
- def removeForwardIndexEntry(self, entry, documentId):
- """Take the entry provided and remove any reference to documentId
- in its entry in the index."""
- global _marker
- indexRow = self._index.get(entry, _marker)
- if indexRow is not _marker:
- try:
- indexRow.remove(documentId)
- if not indexRow:
- del self._index[entry]
- try: self.__len__.change(-1)
- except AttributeError: pass # pre-BTrees-module instance
- except AttributeError:
- # index row is an int
- del self._index[entry]
- try: self.__len__.change(-1)
- except AttributeError: pass # pre-BTrees-module instance
- except:
- LOG(self.__class__.__name__, ERROR,
- ('unindex_object could not remove '
- 'documentId %s from index %s. This '
- 'should not happen.'
- % (str(documentId), str(self.id))), '',
- sys.exc_info())
- else:
- LOG(self.__class__.__name__, ERROR,
- ('unindex_object tried to retrieve set %s '
- 'from index %s but couldn\'t. This '
- 'should not happen.' % (repr(entry), str(self.id))))
-
-
- def insertForwardIndexEntry(self, entry, documentId):
- """Take the entry provided and put it in the correct place
- in the forward index.
-
- This will also deal with creating the entire row if necessary."""
- global _marker
- indexRow = self._index.get(entry, _marker)
-
- # Make sure there's actually a row there already. If not, create
- # an IntSet and stuff it in first.
- if indexRow is _marker:
- self._index[entry] = documentId
- try: self.__len__.change(1)
- except AttributeError: pass # pre-BTrees-module instance
- else:
- try: indexRow.insert(documentId)
- except AttributeError:
- # index row is an int
- indexRow=IITreeSet((indexRow, documentId))
- self._index[entry] = indexRow
-
- def index_object(self, documentId, obj, threshold=None):
- """ index and object 'obj' with integer id 'documentId'"""
- global _marker
- returnStatus = 0
-
- # First we need to see if there's anything interesting to look at
- # self.id is the name of the index, which is also the name of the
- # attribute we're interested in. If the attribute is callable,
- # we'll do so.
- try:
- datum = getattr(obj, self.id)
- if callable(datum):
- datum = datum()
- except AttributeError:
- datum = _marker
-
- # We don't want to do anything that we don't have to here, so we'll
- # check to see if the new and existing information is the same.
- oldDatum = self._unindex.get(documentId, _marker)
- if datum != oldDatum:
- if oldDatum is not _marker:
- self.removeForwardIndexEntry(oldDatum, documentId)
-
- if datum is not _marker:
- self.insertForwardIndexEntry(datum, documentId)
- self._unindex[documentId] = datum
-
- returnStatus = 1
-
- return returnStatus
-
- def unindex_object(self, documentId):
- """ Unindex the object with integer id 'documentId' and don't
- raise an exception if we fail """
-
- global _marker
- unindexRecord = self._unindex.get(documentId, _marker)
- if unindexRecord is _marker:
- return None
-
- self.removeForwardIndexEntry(unindexRecord, documentId)
-
- try:
- del self._unindex[documentId]
- except:
- LOG('UnIndex', ERROR, 'Attempt to unindex nonexistent document'
- ' with id %s' % documentId)
-
- def _apply_index(self, request, cid='', type=type, None=None):
- """Apply the index to query parameters given in the request arg.
-
- The request argument should be a mapping object.
-
- If the request does not have a key which matches the "id" of
- the index instance, then None is returned.
-
- If the request *does* have a key which matches the "id" of
- the index instance, one of a few things can happen:
-
- - if the value is a blank string, None is returned (in
- order to support requests from web forms where
- you can't tell a blank string from empty).
-
- - if the value is a nonblank string, turn the value into
- a single-element sequence, and proceed.
-
- - if the value is a sequence, return a union search.
-
- If the request contains a parameter with the name of the
- column + '_usage', it is sniffed for information on how to
- handle applying the index.
-
- If None is not returned as a result of the abovementioned
- constraints, two objects are returned. The first object is a
- ResultSet containing the record numbers of the matching
- records. The second object is a tuple containing the names of
- all data fields used.
-
- FAQ answer: to search a Field Index for documents that
- have a blank string as their value, wrap the request value
- up in a tuple ala: request = {'id':('',)}
-
- """
- id = self.id #name of the column
-
- cidid = "%s/%s" % (cid,id)
-
- # i have no f'ing clue what this cdid stuff is for - chrism
- if request.has_key(cidid):
- keys = request[cidid]
- elif request.has_key(id):
- keys = request[id]
- else:
- return None
-
- if type(keys) not in (ListType, TupleType):
- if keys == '':
- return None
- else:
- keys = [keys]
-
- index = self._index
- r = None
- opr = None
-
- if request.has_key(id+'_usage'):
- # see if any usage params are sent to field
- opr=string.split(string.lower(request[id+"_usage"]),':')
- opr, opr_args=opr[0], opr[1:]
-
- if opr=="range": # range search
- if 'min' in opr_args: lo = min(keys)
- else: lo = None
- if 'max' in opr_args: hi = max(keys)
- else: hi = None
- if hi:
- setlist = index.items(lo,hi)
- else:
- setlist = index.items(lo)
-
- for k, set in setlist:
- if type(set) is IntType:
- set = IISet((set,))
- r = union(r, set)
- else: # not a range search
- for key in keys:
- set=index.get(key, None)
- if set is not None:
- if type(set) is IntType:
- set = IISet((set,))
- r = union(r, set)
-
- if type(r) is IntType: r=IISet((r,))
- if r is None:
- return IISet(), (id,)
- else:
- return r, (id,)
-
- def hasUniqueValuesFor(self, name):
- ' has unique values for column NAME '
- if name == self.id:
- return 1
- else:
- return 0
-
-
- def uniqueValues(self, name=None, withLengths=0):
- """\
- returns the unique values for name
-
- if withLengths is true, returns a sequence of
- tuples of (value, length)
- """
- if name is None:
- name = self.id
- elif name != self.id:
- return []
-
- if not withLengths:
- return tuple(self._index.keys())
- else:
- rl=[]
- for i in self._index.keys():
- set = self._index[i]
- if type(set) is IntType:
- l = 1
- else:
- l = len(set)
- rl.append((i, l))
- return tuple(rl)
-
- def keyForDocument(self, id):
- return self._unindex[id]
-
- def items(self):
- items = []
- for k,v in self._index.items():
- if type(v) is IntType:
- v = IISet((v,))
- items.append((k, v))
- return items
index_html = DTMLFile('dtml/index', globals())