Commit 1e40bbb9 authored by Michel Pelletier's avatar Michel Pelletier

Added ability to index an object

parent 89721d84
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
############################################################################## ##############################################################################
"""Simple column indices""" """Simple column indices"""
__version__='$Revision: 1.22 $'[11:-2] __version__='$Revision: 1.23 $'[11:-2]
from Globals import Persistent from Globals import Persistent
from BTree import BTree from BTree import BTree
...@@ -96,6 +96,7 @@ import string ...@@ -96,6 +96,7 @@ import string
ListType=type([]) ListType=type([])
StringType=type('s') StringType=type('s')
def nonEmpty(s): def nonEmpty(s):
"returns true if a non-empty string or any other (nonstring) type" "returns true if a non-empty string or any other (nonstring) type"
if type(s) is StringType: if type(s) is StringType:
...@@ -104,29 +105,37 @@ def nonEmpty(s): ...@@ -104,29 +105,37 @@ def nonEmpty(s):
else: else:
return 1 return 1
class Index(Persistent): class Index(Persistent):
"""Index object interface""" """Index object interface"""
def __init__(self,data=None,schema=None,id=None): def __init__(self, data=None, schema=None, id=None,
ignore_ex=None, call_methods=None):
"""Create an index """Create an index
The arguments are: The arguments are:
'data' -- a mapping from integer object ids to objects or records, 'data' -- a mapping from integer object ids to objects or
records,
'schema' -- a mapping from item name to index into data
records. If 'data' is a mapping to objects, then schema
should ne 'None'.
'schema' -- a mapping from item name to index into data records. 'id' -- the name of the item attribute to index. This is
If 'data' is a mapping to objects, then schema should ne 'None'. either an attribute name or a record key.
'id' -- the name of the item attribute to index. This is either
an attribute name or a record key.
""" """
###################################################################### ######################################################################
# For b/w compatability, have to allow __init__ calls with zero args # For b/w compatability, have to allow __init__ calls with zero args
if not data==schema==id==None:
self._data=data if not data==schema==id==ignore_ex==call_methods==None:
self._schema=schema self._data = data
self.id=id self._schema = schema
self._index=BTree() self.id = id
self.ignore_ex=ignore_ex
self.call_methods=call_methods
self._index = BTree()
self._reindex() self._reindex()
else: else:
...@@ -135,6 +144,7 @@ class Index(Persistent): ...@@ -135,6 +144,7 @@ class Index(Persistent):
# for b/w compatability # for b/w compatability
_init = __init__ _init = __init__
def dpHasUniqueValuesFor(self, name): def dpHasUniqueValuesFor(self, name):
' has unique values for column NAME ' ' has unique values for column NAME '
if name == self.id: if name == self.id:
...@@ -142,6 +152,7 @@ class Index(Persistent): ...@@ -142,6 +152,7 @@ class Index(Persistent):
else: else:
return 0 return 0
def dpUniqueValues(self, name=None, withLengths=0): def dpUniqueValues(self, name=None, withLengths=0):
"""\ """\
returns the unique values for name returns the unique values for name
...@@ -163,10 +174,12 @@ class Index(Persistent): ...@@ -163,10 +174,12 @@ class Index(Persistent):
else: rl.append((i, len(self._index[i]))) else: rl.append((i, len(self._index[i])))
return tuple(rl) return tuple(rl)
def clear(self): def clear(self):
self._index=BTree() self._index = BTree()
def _reindex(self,start=0): def _reindex(self, start=0):
"""Recompute index data for data with ids >= start.""" """Recompute index data for data with ids >= start."""
index=self._index index=self._index
...@@ -174,12 +187,12 @@ class Index(Persistent): ...@@ -174,12 +187,12 @@ class Index(Persistent):
if not start: index.clear() if not start: index.clear()
id=self.id id = self.id
if self._schema is None: if self._schema is None:
f=getattr f=getattr
else: else:
f=operator.__getitem__ f = operator.__getitem__
id=self._schema[id] id = self._schema[id]
for i,row in self._data.items(start): for i,row in self._data.items(start):
k=f(row,id) k=f(row,id)
...@@ -187,59 +200,73 @@ class Index(Persistent): ...@@ -187,59 +200,73 @@ class Index(Persistent):
if k is None or k == MV: continue if k is None or k == MV: continue
set=get(k) set=get(k)
if set is None: index[k]=set=intSet() if set is None: index[k] = set = intSet()
set.insert(i) set.insert(i)
def index_item(self,i):
def index_item(self, i, obj=None):
"""Recompute index data for data with ids >= start.""" """Recompute index data for data with ids >= start."""
index=self._index index = self._index
id=self.id id = self.id
if self._schema is None: if self._schema is None:
f=getattr f = getattr
else: else:
f=operator.__getitem__ f = operator.__getitem__
id=self._schema[id] id = self._schema[id]
row=self._data[i] if obj is None:
k=f(row,id) obj = self._data[i]
if self.call_methods:
k = f(obj, id)()
else:
k = f(obj, id)
if k is None or k == MV: return if k is None or k == MV: return
set=index.get(k) set = index.get(k)
if set is None: index[k]=set=intSet() if set is None: index[k] = set = intSet()
set.insert(i) set.insert(i)
def unindex_item(self,i):
def unindex_item(self, i, obj=None):
"""Recompute index data for data with ids >= start.""" """Recompute index data for data with ids >= start."""
index=self._index index = self._index
id=self.id id = self.id
if self._schema is None: if self._schema is None:
f=getattr f = getattr
else: else:
f=operator.__getitem__ f = operator.__getitem__
id=self._schema[id] id = self._schema[id]
row=self._data[i] if obj is None:
k=f(row,id) obj = self._data[i]
if self.call_methods:
k = f(obj, id)()
else:
k = f(obj, id)
set=index.get(k) set = index.get(k)
if set is not None: set.remove(i) if set is not None: set.remove(i)
def _apply_index(self, request, cid=''): def _apply_index(self, request, cid=''):
"""Apply the index to query parameters given in the argument, request """Apply the index to query parameters given in the argument,
request
The argument should be a mapping object. The argument should be a mapping object.
If the request does not contain the needed parameters, then None is If the request does not contain the needed parameters, then
returned. None is returned.
If the request contains a parameter with the name of the column If the request contains a parameter with the name of the
+ '_usage', it is sniffed for information on how to handle applying column + '_usage', it is sniffed for information on how to
the index. handle applying the index.
Otherwise two objects are returned. The first object is a Otherwise two objects are returned. The first object is a
ResultSet containing the record numbers of the matching ResultSet containing the record numbers of the matching
...@@ -247,19 +274,19 @@ class Index(Persistent): ...@@ -247,19 +274,19 @@ class Index(Persistent):
all data fields used. all data fields used.
""" """
id=self.id #name of the column id = self.id #name of the column
cidid="%s/%s" % (cid,id) cidid = "%s/%s" % (cid,id)
has_key=request.has_key has_key = request.has_key
if has_key(cidid): keys=request[cidid] if has_key(cidid): keys = request[cidid]
elif has_key(id): keys=request[id] elif has_key(id): keys = request[id]
else: return None else: return None
if type(keys) is not ListType: keys=[keys] if type(keys) is not ListType: keys=[keys]
index=self._index index = self._index
r=None r = None
anyTrue=0 anyTrue = 0
opr=None opr = None
if request.has_key(id+'_usage'): if request.has_key(id+'_usage'):
# see if any usage params are sent to field # see if any usage params are sent to field
...@@ -267,26 +294,26 @@ class Index(Persistent): ...@@ -267,26 +294,26 @@ class Index(Persistent):
opr, opr_args=opr[0], opr[1:] opr, opr_args=opr[0], opr[1:]
if opr=="range": if opr=="range":
if 'min' in opr_args: lo=min(keys) if 'min' in opr_args: lo = min(keys)
else: lo=None else: lo = None
if 'max' in opr_args: hi=max(keys) if 'max' in opr_args: hi = max(keys)
else: hi=None else: hi = None
anyTrue=1 anyTrue=1
try: try:
if hi: setlist=index.items(lo,hi) if hi: setlist = index.items(lo,hi)
else: setlist=index.items(lo) else: setlist = index.items(lo)
for k,set in setlist: for k,set in setlist:
if r is None: r=set if r is None: r = set
else: r=r.union(set) else: r = r.union(set)
except KeyError: pass except KeyError: pass
else: #not a range else: #not a range
get=index.get get = index.get
for key in keys: for key in keys:
if key: anyTrue=1 if key: anyTrue = 1
set=get(key) set=get(key)
if set is not None: if set is not None:
if r is None: r=set if r is None: r = set
else: r = r.union(set) else: r = r.union(set)
if r is None: if r is None:
...@@ -294,3 +321,19 @@ class Index(Persistent): ...@@ -294,3 +321,19 @@ class Index(Persistent):
else: return None else: return None
return r, (id,) return r, (id,)
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment