[gen] Cleaner and more robust approach when using Zope database indexes.
This commit is contained in:
		
							parent
							
								
									5c2d94236f
								
							
						
					
					
						commit
						c2eaab4b44
					
				
					 6 changed files with 75 additions and 30 deletions
				
			
		| 
						 | 
					@ -33,6 +33,13 @@ def initMasterValue(v):
 | 
				
			||||||
    else: res = v
 | 
					    else: res = v
 | 
				
			||||||
    return [str(v) for v in res]
 | 
					    return [str(v) for v in res]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Default Appy indexes ---------------------------------------------------------
 | 
				
			||||||
 | 
					defaultIndexes = {
 | 
				
			||||||
 | 
					    'State': 'FieldIndex', 'UID': 'FieldIndex', 'Title': 'ZCTextIndex',
 | 
				
			||||||
 | 
					    'SortableTitle': 'FieldIndex', 'SearchableText': 'ZCTextIndex',
 | 
				
			||||||
 | 
					    'Creator': 'FieldIndex', 'Created': 'DateIndex', 'ClassName': 'FieldIndex',
 | 
				
			||||||
 | 
					    'Allowed': 'KeywordIndex'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Descriptor classes used for refining descriptions of elements in types
 | 
					# Descriptor classes used for refining descriptions of elements in types
 | 
				
			||||||
# (pages, groups,...) ----------------------------------------------------------
 | 
					# (pages, groups,...) ----------------------------------------------------------
 | 
				
			||||||
class Page:
 | 
					class Page:
 | 
				
			||||||
| 
						 | 
					@ -961,14 +968,17 @@ class Type:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                return method(obj, self)
 | 
					                return method(obj, self)
 | 
				
			||||||
            except Exception, e:
 | 
					            except Exception, e:
 | 
				
			||||||
                # Log the initial error.
 | 
					                if raiseOnError:
 | 
				
			||||||
                obj.log(tb, type='error')
 | 
					                    # Raise the initial error.
 | 
				
			||||||
                if raiseOnError: raise te
 | 
					                    raise te
 | 
				
			||||||
                else: return str(te)
 | 
					                else:
 | 
				
			||||||
 | 
					                    obj.log(tb, type='error')
 | 
				
			||||||
 | 
					                    return str(te)
 | 
				
			||||||
        except Exception, e:
 | 
					        except Exception, e:
 | 
				
			||||||
            obj.log(Traceback.get(), type='error')
 | 
					 | 
				
			||||||
            if raiseOnError: raise e
 | 
					            if raiseOnError: raise e
 | 
				
			||||||
            else: return str(e)
 | 
					            else:
 | 
				
			||||||
 | 
					                obj.log(Traceback.get(), type='error')
 | 
				
			||||||
 | 
					                return str(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def process(self, obj):
 | 
					    def process(self, obj):
 | 
				
			||||||
        '''This method is a general hook allowing a field to perform some
 | 
					        '''This method is a general hook allowing a field to perform some
 | 
				
			||||||
| 
						 | 
					@ -2122,7 +2132,7 @@ class Computed(Type):
 | 
				
			||||||
            return self.callMacro(obj, self.method)
 | 
					            return self.callMacro(obj, self.method)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # self.method is a method that will return the field value
 | 
					            # self.method is a method that will return the field value
 | 
				
			||||||
            return self.callMethod(obj, self.method, raiseOnError=False)
 | 
					            return self.callMethod(obj, self.method, raiseOnError=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFormattedValue(self, obj, value):
 | 
					    def getFormattedValue(self, obj, value):
 | 
				
			||||||
        if not isinstance(value, basestring): return str(value)
 | 
					        if not isinstance(value, basestring): return str(value)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,10 +163,10 @@ class ZopeInstaller:
 | 
				
			||||||
                    catalog.addIndex(indexName, indexType)
 | 
					                    catalog.addIndex(indexName, indexType)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    catalog.addIndex(indexName, indexType,extra=ZCTextIndexInfo)
 | 
					                    catalog.addIndex(indexName, indexType,extra=ZCTextIndexInfo)
 | 
				
			||||||
 | 
					                # Indexing database content based on this index.
 | 
				
			||||||
                catalog.reindexIndex(indexName, self.app.REQUEST)
 | 
					                catalog.reindexIndex(indexName, self.app.REQUEST)
 | 
				
			||||||
                logger.info('Created index "%s" of type "%s"...' % \
 | 
					                logger.info('Created index "%s" of type "%s"...' % \
 | 
				
			||||||
                            (indexName, indexType))
 | 
					                            (indexName, indexType))
 | 
				
			||||||
                            # Indexing database content based on this index.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    lexiconInfos = [
 | 
					    lexiconInfos = [
 | 
				
			||||||
        appy.Object(group='Case Normalizer', name='Case Normalizer'),
 | 
					        appy.Object(group='Case Normalizer', name='Case Normalizer'),
 | 
				
			||||||
| 
						 | 
					@ -188,19 +188,11 @@ class ZopeInstaller:
 | 
				
			||||||
                              elements=self.lexiconInfos)
 | 
					                              elements=self.lexiconInfos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create or update Appy-wide indexes and field-related indexes
 | 
					        # Create or update Appy-wide indexes and field-related indexes
 | 
				
			||||||
        indexInfo = {'State': 'FieldIndex', 'UID': 'FieldIndex',
 | 
					        indexInfo = gen.defaultIndexes.copy()
 | 
				
			||||||
                     'Title': 'ZCTextIndex', 'SortableTitle': 'FieldIndex',
 | 
					 | 
				
			||||||
                     'SearchableText': 'ZCTextIndex', 'Creator': 'FieldIndex',
 | 
					 | 
				
			||||||
                     'Created': 'DateIndex', 'ClassName': 'FieldIndex',
 | 
					 | 
				
			||||||
                     'Allowed': 'KeywordIndex'}
 | 
					 | 
				
			||||||
        tool = self.app.config
 | 
					        tool = self.app.config
 | 
				
			||||||
        for className in self.config.attributes.iterkeys():
 | 
					        for className in self.config.attributes.iterkeys():
 | 
				
			||||||
            wrapperClass = tool.getAppyClass(className, wrapper=True)
 | 
					            wrapperClass = tool.getAppyClass(className, wrapper=True)
 | 
				
			||||||
            for appyType in wrapperClass.__fields__:
 | 
					            indexInfo.update(wrapperClass.getIndexes(includeDefaults=False))
 | 
				
			||||||
                if not appyType.indexed or (appyType.name == 'title'): continue
 | 
					 | 
				
			||||||
                n = appyType.name
 | 
					 | 
				
			||||||
                indexName = 'get%s%s' % (n[0].upper(), n[1:])
 | 
					 | 
				
			||||||
                indexInfo[indexName] = appyType.getIndexType()
 | 
					 | 
				
			||||||
        self.installIndexes(indexInfo)
 | 
					        self.installIndexes(indexInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getAddPermission(self, className):
 | 
					    def getAddPermission(self, className):
 | 
				
			||||||
| 
						 | 
					@ -345,7 +337,6 @@ class ZopeInstaller:
 | 
				
			||||||
                appyTool.log('Translation "%s" updated from "%s".' % \
 | 
					                appyTool.log('Translation "%s" updated from "%s".' % \
 | 
				
			||||||
                             (translation.id, poName))
 | 
					                             (translation.id, poName))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def configureSessions(self):
 | 
					    def configureSessions(self):
 | 
				
			||||||
        '''Configure the session machinery.'''
 | 
					        '''Configure the session machinery.'''
 | 
				
			||||||
        # Register a function warning us when a session object is deleted. When
 | 
					        # Register a function warning us when a session object is deleted. When
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -321,7 +321,11 @@ class BaseMixin:
 | 
				
			||||||
            if indexes:
 | 
					            if indexes:
 | 
				
			||||||
                catalog.catalog_object(self, path, idxs=indexes)
 | 
					                catalog.catalog_object(self, path, idxs=indexes)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                catalog.catalog_object(self, path)
 | 
					                # Get the list of indexes that apply on this object. Else, Zope
 | 
				
			||||||
 | 
					                # will reindex all indexes defined in the catalog, and through
 | 
				
			||||||
 | 
					                # acquisition, wrong methods can be called on wrong objects.
 | 
				
			||||||
 | 
					                iNames = self.wrapperClass.getIndexes().keys()
 | 
				
			||||||
 | 
					                catalog.catalog_object(self, path, idxs=iNames)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def say(self, msg, type='info'):
 | 
					    def say(self, msg, type='info'):
 | 
				
			||||||
        '''Prints a p_msg in the user interface. p_logLevel may be "info",
 | 
					        '''Prints a p_msg in the user interface. p_logLevel may be "info",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,7 +143,7 @@
 | 
				
			||||||
    <table><tr valign="top">
 | 
					    <table><tr valign="top">
 | 
				
			||||||
      <tal:comment replace="nothing">If there is no object...</tal:comment>
 | 
					      <tal:comment replace="nothing">If there is no object...</tal:comment>
 | 
				
			||||||
      <tal:noObject condition="not:objs">
 | 
					      <tal:noObject condition="not:objs">
 | 
				
			||||||
        <td tal:content="python: _('no_ref')"></td>
 | 
					        <td class="discreet" tal:content="python: _('no_ref')"></td>
 | 
				
			||||||
        <td><metal:plusIcon use-macro="app/ui/widgets/ref/macros/plusIcon"/></td>
 | 
					        <td><metal:plusIcon use-macro="app/ui/widgets/ref/macros/plusIcon"/></td>
 | 
				
			||||||
      </tal:noObject>
 | 
					      </tal:noObject>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,7 +171,7 @@
 | 
				
			||||||
  <metal:nav use-macro="here/ui/navigate/macros/appyNavigate"/>
 | 
					  <metal:nav use-macro="here/ui/navigate/macros/appyNavigate"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <tal:comment replace="nothing">No object is present</tal:comment>
 | 
					  <tal:comment replace="nothing">No object is present</tal:comment>
 | 
				
			||||||
  <p tal:condition="not:objs" tal:content="python: _('no_ref')"></p>
 | 
					  <p class="discreet" tal:condition="not:objs" tal:content="python: _('no_ref')"></p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <table width="100%" tal:condition="python: objs"
 | 
					  <table width="100%" tal:condition="python: objs"
 | 
				
			||||||
         tal:attributes="class python:test(innerRef, 'innerAppyTable', '')">
 | 
					         tal:attributes="class python:test(innerRef, 'innerAppyTable', '')">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -168,20 +168,41 @@ class ToolWrapper(AbstractWrapper):
 | 
				
			||||||
            # reindex all Appy-managed objects, ie those in folders "config"
 | 
					            # reindex all Appy-managed objects, ie those in folders "config"
 | 
				
			||||||
            # and "data".
 | 
					            # and "data".
 | 
				
			||||||
            # First, clear the catalog.
 | 
					            # First, clear the catalog.
 | 
				
			||||||
 | 
					            self.log('Recomputing the whole catalog...')
 | 
				
			||||||
            app = self.o.getParentNode()
 | 
					            app = self.o.getParentNode()
 | 
				
			||||||
            app.catalog._catalog.clear()
 | 
					            app.catalog._catalog.clear()
 | 
				
			||||||
            app.config.reindex()
 | 
					 | 
				
			||||||
            nb = 1
 | 
					            nb = 1
 | 
				
			||||||
 | 
					            failed = []
 | 
				
			||||||
            for obj in app.config.objectValues():
 | 
					            for obj in app.config.objectValues():
 | 
				
			||||||
                nb += self.refreshCatalog(startObject=obj)
 | 
					                subNb, subFailed = self.refreshCatalog(startObject=obj)
 | 
				
			||||||
 | 
					                nb += subNb
 | 
				
			||||||
 | 
					                failed += subFailed
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                app.config.reindex()
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                failed.append(app.config)
 | 
				
			||||||
            # Then, refresh objects in the "data" folder.
 | 
					            # Then, refresh objects in the "data" folder.
 | 
				
			||||||
            for obj in app.data.objectValues():
 | 
					            for obj in app.data.objectValues():
 | 
				
			||||||
                nb += self.refreshCatalog(startObject=obj)
 | 
					                subNb, subFailed = self.refreshCatalog(startObject=obj)
 | 
				
			||||||
            print '%d object(s) were reindexed.' % nb
 | 
					                nb += subNb
 | 
				
			||||||
 | 
					                failed += subFailed
 | 
				
			||||||
 | 
					            # Re-try to index all objects for which reindexation has failed.
 | 
				
			||||||
 | 
					            for obj in failed: obj.reindex()
 | 
				
			||||||
 | 
					            if failed:
 | 
				
			||||||
 | 
					                failMsg = ' (%d retried)' % len(failed)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                failMsg = ''
 | 
				
			||||||
 | 
					            self.log('%d object(s) were reindexed%s.' % (nb, failMsg))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            startObject.reindex()
 | 
					 | 
				
			||||||
            nb = 1
 | 
					            nb = 1
 | 
				
			||||||
 | 
					            failed = []
 | 
				
			||||||
            for obj in startObject.objectValues():
 | 
					            for obj in startObject.objectValues():
 | 
				
			||||||
                nb += self.refreshCatalog(startObject=obj)
 | 
					                subNb, subFailed = self.refreshCatalog(startObject=obj)
 | 
				
			||||||
            return nb
 | 
					                nb += subNb
 | 
				
			||||||
 | 
					                failed += subFailed
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                startObject.reindex()
 | 
				
			||||||
 | 
					            except Exception, e:
 | 
				
			||||||
 | 
					                failed.append(startObject)
 | 
				
			||||||
 | 
					            return nb, failed
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import os, os.path, mimetypes
 | 
					import os, os.path, mimetypes
 | 
				
			||||||
import appy.pod
 | 
					import appy.pod
 | 
				
			||||||
from appy.gen import Type, Search, Ref, String, WorkflowAnonymous
 | 
					from appy.gen import Type, Search, Ref, String, WorkflowAnonymous, \
 | 
				
			||||||
 | 
					                     defaultIndexes
 | 
				
			||||||
from appy.gen.utils import createObject
 | 
					from appy.gen.utils import createObject
 | 
				
			||||||
from appy.shared.utils import getOsTempFolder, executeCommand, \
 | 
					from appy.shared.utils import getOsTempFolder, executeCommand, \
 | 
				
			||||||
                              normalizeString, sequenceTypes
 | 
					                              normalizeString, sequenceTypes
 | 
				
			||||||
| 
						 | 
					@ -59,6 +60,24 @@ class AbstractWrapper(object):
 | 
				
			||||||
        if not res: res = cfg.defaultAddRoles
 | 
					        if not res: res = cfg.defaultAddRoles
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def getIndexes(klass, includeDefaults=True):
 | 
				
			||||||
 | 
					        '''Returns a dict whose keys are the names of the indexes that are
 | 
				
			||||||
 | 
					           applicable to instances of this class, and whose values are the
 | 
				
			||||||
 | 
					           (Zope) types of those indexes.'''
 | 
				
			||||||
 | 
					        # Start with the standard indexes applicable for any Appy class.
 | 
				
			||||||
 | 
					        if includeDefaults:
 | 
				
			||||||
 | 
					            res = defaultIndexes.copy()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            res = {}
 | 
				
			||||||
 | 
					        # Add the indexed fields found on this class
 | 
				
			||||||
 | 
					        for field in klass.__fields__:
 | 
				
			||||||
 | 
					            if not field.indexed or (field.name == 'title'): continue
 | 
				
			||||||
 | 
					            n = field.name
 | 
				
			||||||
 | 
					            indexName = 'get%s%s' % (n[0].upper(), n[1:])
 | 
				
			||||||
 | 
					            res[indexName] = field.getIndexType()
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # --------------------------------------------------------------------------
 | 
					    # --------------------------------------------------------------------------
 | 
				
			||||||
    # Instance methods
 | 
					    # Instance methods
 | 
				
			||||||
    # --------------------------------------------------------------------------
 | 
					    # --------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue