@@ -29,6 +29,16 @@ def __init__(self, config, journaltag=None):
2929 self ._db = self .__open ()
3030 self .indexer = Indexer (self .config .DATABASE )
3131 os .umask (0002 )
32+ def post_init (self ):
33+ if self .indexer .should_reindex ():
34+ self .reindex ()
35+
36+ def reindex (self ):
37+ for klass in self .classes .values ():
38+ for nodeid in klass .list ():
39+ klass .index (nodeid )
40+ self .indexer .save_index ()
41+
3242
3343 # --- defined in ping's spec
3444 def __getattr__ (self , classname ):
@@ -51,6 +61,7 @@ def commit(self):
5161 self ._db .commit ()
5262 for cl in self .classes .values ():
5363 cl ._commit ()
64+ self .indexer .save_index ()
5465 else :
5566 raise RuntimeError , "metakit is open RO"
5667 self .dirty = 0
@@ -68,7 +79,7 @@ def hasnode(self, classname, nodeid):
6879 def pack (self , pack_before ):
6980 pass
7081 def addclass (self , cl ):
71- self .classes [cl .name ] = cl
82+ self .classes [cl .classname ] = cl
7283 def addjournal (self , tablenm , nodeid , action , params ):
7384 tblid = self .tables .find (name = tablenm )
7485 if tblid == - 1 :
@@ -136,6 +147,8 @@ def __open(self):
136147 self .fastopen = 1
137148 else :
138149 self .__RW = 1
150+ if not self .fastopen :
151+ self .__RW = 1
139152 db = metakit .storage (db , self .__RW )
140153 hist = db .view ('history' )
141154 tables = db .view ('tables' )
@@ -182,7 +195,7 @@ class Class: # no, I'm not going to subclass the existing!
182195 privateprops = None
183196 def __init__ (self , db , classname , ** properties ):
184197 self .db = weakref .proxy (db )
185- self .name = classname
198+ self .classname = classname
186199 self .keyname = None
187200 self .ruprops = properties
188201 self .privateprops = { 'id' : hyperdb .String (),
@@ -245,7 +258,7 @@ def get(self, nodeid, propname, default=_marker, cache=1):
245258 if ndx is None :
246259 ndx = view .find (id = id )
247260 if ndx < 0 :
248- raise IndexError , "%s has no node %s" % (self .name , nodeid )
261+ raise IndexError , "%s has no node %s" % (self .classname , nodeid )
249262 self .idcache [id ] = ndx
250263 raw = getattr (view [ndx ], propname )
251264 rutyp = self .ruprops .get (propname , None )
@@ -273,10 +286,10 @@ def set(self, nodeid, **propvalues):
273286 id = int (nodeid )
274287 ndx = view .find (id = id )
275288 if ndx < 0 :
276- raise IndexError , "%s has no node %s" % (self .name , nodeid )
289+ raise IndexError , "%s has no node %s" % (self .classname , nodeid )
277290 row = view [ndx ]
278291 if row ._isdel :
279- raise IndexError , "%s has no node %s" % (self .name , nodeid )
292+ raise IndexError , "%s has no node %s" % (self .classname , nodeid )
280293 oldnode = self .uncommitted .setdefault (id , {})
281294 changes = {}
282295
@@ -335,11 +348,11 @@ def set(self, nodeid, **propvalues):
335348 if prop .do_journal :
336349 # register the unlink with the old linked node
337350 if oldvalue :
338- self .db .addjournal (link_class , value , _UNLINK , (self .name , str (row .id ), key ))
351+ self .db .addjournal (link_class , value , _UNLINK , (self .classname , str (row .id ), key ))
339352
340353 # register the link with the newly linked node
341354 if value :
342- self .db .addjournal (link_class , value , _LINK , (self .name , str (row .id ), key ))
355+ self .db .addjournal (link_class , value , _LINK , (self .classname , str (row .id ), key ))
343356
344357 elif isinstance (prop , hyperdb .Multilink ):
345358 if type (value ) != _LISTTYPE :
@@ -369,7 +382,7 @@ def set(self, nodeid, **propvalues):
369382 rmvd .append (id )
370383 # register the unlink with the old linked node
371384 if prop .do_journal :
372- self .db .addjournal (link_class , id , _UNLINK , (self .name , str (row .id ), key ))
385+ self .db .addjournal (link_class , id , _UNLINK , (self .classname , str (row .id ), key ))
373386
374387 # handle additions
375388 adds = []
@@ -381,7 +394,7 @@ def set(self, nodeid, **propvalues):
381394 adds .append (id )
382395 # register the link with the newly linked node
383396 if prop .do_journal :
384- self .db .addjournal (link_class , id , _LINK , (self .name , str (row .id ), key ))
397+ self .db .addjournal (link_class , id , _LINK , (self .classname , str (row .id ), key ))
385398
386399 sv = getattr (row , key )
387400 i = 0
@@ -402,6 +415,8 @@ def set(self, nodeid, **propvalues):
402415 changes [key ] = oldvalue
403416 if hasattr (prop , 'isfilename' ) and prop .isfilename :
404417 propvalues [key ] = os .path .basename (value )
418+ if prop .indexme :
419+ self .db .indexer .add_text ((self .classname , nodeid , key ), value , 'text/plain' )
405420
406421 elif isinstance (prop , hyperdb .Password ):
407422 if not isinstance (value , password .Password ):
@@ -437,11 +452,13 @@ def set(self, nodeid, **propvalues):
437452 if not row .creator :
438453 row .creator = self .db .curuserid
439454
455+ #XXX
456+ print "back_metakit.Class.set - dirty"
440457 self .db .dirty = 1
441458 if isnew :
442- self .db .addjournal (self .name , nodeid , _CREATE , {})
459+ self .db .addjournal (self .classname , nodeid , _CREATE , {})
443460 else :
444- self .db .addjournal (self .name , nodeid , _SET , changes )
461+ self .db .addjournal (self .classname , nodeid , _SET , changes )
445462
446463 def retire (self , nodeid ):
447464 view = self .getview (1 )
@@ -452,26 +469,26 @@ def retire(self, nodeid):
452469 oldvalues = self .uncommitted .setdefault (row .id , {})
453470 oldval = oldvalues ['_isdel' ] = row ._isdel
454471 row ._isdel = 1
455- self .db .addjournal (self .name , nodeid , _RETIRE , {})
472+ self .db .addjournal (self .classname , nodeid , _RETIRE , {})
456473 iv = self .getindexview (1 )
457474 ndx = iv .find (k = getattr (row , self .keyname ),i = row .id )
458475 if ndx > - 1 :
459476 iv .delete (ndx )
460477 self .db .dirty = 1
461478 def history (self , nodeid ):
462- return self .db .gethistory (self .name , nodeid )
479+ return self .db .gethistory (self .classname , nodeid )
463480 def setkey (self , propname ):
464481 if self .keyname :
465482 if propname == self .keyname :
466483 return
467- raise ValueError , "%s already indexed on %s" % (self .name , self .keyname )
484+ raise ValueError , "%s already indexed on %s" % (self .classname , self .keyname )
468485 # first setkey for this run
469486 self .keyname = propname
470- iv = self .db ._db .view ('_%s' % self .name )
487+ iv = self .db ._db .view ('_%s' % self .classname )
471488 if self .db .fastopen or iv .structure ():
472489 return
473490 # very first setkey ever
474- iv = self .db ._db .getas ('_%s[k:S,i:I]' % self .name )
491+ iv = self .db ._db .getas ('_%s[k:S,i:I]' % self .classname )
475492 iv = iv .ordered (1 )
476493 #XXX
477494 print "setkey building index"
@@ -514,6 +531,8 @@ def find(self, **propspec):
514531
515532 vws = []
516533 for propname , ids in propspec :
534+ if type (ids ) is _STRINGTYPE :
535+ ids = {ids :1 }
517536 prop = self .ruprops [propname ]
518537 view = self .getview ()
519538 if isinstance (prop , hyperdb .Multilink ):
@@ -551,7 +570,7 @@ def getprops(self, protected=1):
551570 def addprop (self , ** properties ):
552571 for key in properties .keys ():
553572 if self .ruprops .has_key (key ):
554- raise ValueError , "%s is already a property of %s" % (key , self .name )
573+ raise ValueError , "%s is already a property of %s" % (key , self .classname )
555574 self .ruprops .update (properties )
556575 view = self .__getview ()
557576 # ---- end of ping's spec
@@ -731,7 +750,17 @@ def stringFind(self, **requirements):
731750 return l
732751
733752 def addjournal (self , nodeid , action , params ):
734- self .db .addjournal (self .name , nodeid , action , params )
753+ self .db .addjournal (self .classname , nodeid , action , params )
754+
755+ def index (self , nodeid ):
756+ ''' Add (or refresh) the node to search indexes '''
757+ # find all the String properties that have indexme
758+ for prop , propclass in self .getprops ().items ():
759+ if isinstance (propclass , hyperdb .String ) and propclass .indexme :
760+ # index them under (classname, nodeid, property)
761+ self .db .indexer .add_text ((self .classname , nodeid , prop ),
762+ str (self .get (nodeid , prop )))
763+
735764 # --- used by Database
736765 def _commit (self ):
737766 """ called post commit of the DB.
@@ -762,24 +791,31 @@ def rollbackaction(self, action):
762791 # --- internal
763792 def __getview (self ):
764793 db = self .db ._db
765- view = db .view (self .name )
794+ view = db .view (self .classname )
766795 if self .db .fastopen :
767796 return view .ordered (1 )
768797 # is the definition the same?
798+ mkprops = view .structure ()
769799 for nm , rutyp in self .ruprops .items ():
770- mkprop = getattr (view , nm , None )
800+ for mkprop in mkprops :
801+ if mkprop .name == nm :
802+ break
803+ else :
804+ mkprop = None
771805 if mkprop is None :
772- #print "%s missing prop %s (%s)" % (self.name , nm, rutyp.__class__.__name__)
806+ #print "%s missing prop %s (%s)" % (self.classname , nm, rutyp.__class__.__name__)
773807 break
774808 if _typmap [rutyp .__class__ ] != mkprop .type :
775- #print "%s - prop %s (%s) has wrong mktyp (%s)" % (self.name , nm, rutyp.__class__.__name__, mkprop.type)
809+ #print "%s - prop %s (%s) has wrong mktyp (%s)" % (self.classname , nm, rutyp.__class__.__name__, mkprop.type)
776810 break
777811 else :
778812 return view .ordered (1 )
779813 # need to create or restructure the mk view
780814 # id comes first, so MK will order it for us
815+ #XXX
816+ print "back_metakit.Class.__getview - dirty!"
781817 self .db .dirty = 1
782- s = ["%s[id:I" % self .name ]
818+ s = ["%s[id:I" % self .classname ]
783819 for nm , rutyp in self .ruprops .items ():
784820 mktyp = _typmap [rutyp .__class__ ]
785821 s .append ('%s:%s' % (nm , mktyp ))
@@ -791,11 +827,11 @@ def __getview(self):
791827 def getview (self , RW = 0 ):
792828 if RW and self .db .isReadOnly ():
793829 self .db .getWriteAccess ()
794- return self .db ._db .view (self .name ).ordered (1 )
830+ return self .db ._db .view (self .classname ).ordered (1 )
795831 def getindexview (self , RW = 0 ):
796832 if RW and self .db .isReadOnly ():
797833 self .db .getWriteAccess ()
798- return self .db ._db .view ("_%s" % self .name ).ordered (1 )
834+ return self .db ._db .view ("_%s" % self .classname ).ordered (1 )
799835
800836def _fetchML (sv ):
801837 l = []
@@ -837,8 +873,11 @@ class FileName(hyperdb.String):
837873}
838874class FileClass (Class ):
839875 ' like Class but with a content property '
876+ default_mime_type = 'text/plain'
840877 def __init__ (self , db , classname , ** properties ):
841878 properties ['content' ] = FileName ()
879+ if not properties .has_key ('type' ):
880+ properties ['type' ] = hyperdb .String ()
842881 Class .__init__ (self , db , classname , ** properties )
843882 def get (self , nodeid , propname , default = _marker , cache = 1 ):
844883 x = Class .get (self , nodeid , propname , default , cache )
@@ -859,22 +898,28 @@ def create(self, **propvalues):
859898 if content .startswith ('/tracker/download.php?' ):
860899 self .set (newid , content = 'http://sourceforge.net' + content )
861900 return newid
862- nm = bnm = '%s%s' % (self .name , newid )
901+ nm = bnm = '%s%s' % (self .classname , newid )
863902 sd = str (int (int (newid ) / 1000 ))
864- d = os .path .join (self .db .config .DATABASE , 'files' , self .name , sd )
903+ d = os .path .join (self .db .config .DATABASE , 'files' , self .classname , sd )
865904 if not os .path .exists (d ):
866905 os .makedirs (d )
867906 nm = os .path .join (d , nm )
868907 open (nm , 'wb' ).write (content )
869908 self .set (newid , content = 'file:' + nm )
870- self . db . indexer . add_files ( d , bnm )
871- self .db .indexer .save_index ( )
909+ mimetype = propvalues . get ( 'type' , self . default_mime_type )
910+ self .db .indexer .add_text (( self . classname , newid , 'content' ), content , mimetype )
872911 def undo (fnm = nm , action1 = os .remove , indexer = self .db .indexer ):
873912 remove (fnm )
874- indexer .purge_entry (fnm , indexer .files , indexer .words )
875913 self .rollbackaction (undo )
876914 return newid
877-
915+ def index (self , nodeid ):
916+ Class .index (self , nodeid )
917+ mimetype = self .get (nodeid , 'type' )
918+ if not mimetype :
919+ mimetype = self .default_mime_type
920+ self .db .indexer .add_text ((self .classname , nodeid , 'content' ),
921+ self .get (nodeid , 'content' ), mimetype )
922+
878923# Yuck - c&p to avoid getting hyperdb.Class
879924class IssueClass (Class ):
880925
@@ -886,7 +931,7 @@ def __init__(self, db, classname, **properties):
886931 dictionary attempts to specify any of these properties or a
887932 "creation" or "activity" property, a ValueError is raised."""
888933 if not properties .has_key ('title' ):
889- properties ['title' ] = hyperdb .String ()
934+ properties ['title' ] = hyperdb .String (indexme = 'yes' )
890935 if not properties .has_key ('messages' ):
891936 properties ['messages' ] = hyperdb .Multilink ("msg" )
892937 if not properties .has_key ('files' ):
0 commit comments