Plone 5.2 - Catalog search used in calculation called by indexer doesn't work when something is being deleted?

I have an indexer called 'calduedate_indexer', which indexes a DateIndex 'calDueDate' for any object that provides an interface ICalibratable. The index is added through setuphandlers and then defined as a metadata column in catalog.xml. Objects that provide ICalibratable can store content types called Calibrations. Calibrations have a calculated property 'next_calibration', which is stored in metadata. An accessor adapter with an interface ICalibrationAccessor is used to retrieve calibration information of a 'Calibratable' content type, such as a calculation for the date of an upcoming calibration.

In the indexer, a function on the accessor called getDueDate is called to get the next calibration by getting calibration records through a portal_catalog search (i.e. getFolderContents on the Calibratable type), returning None if there is no calibration due date.

This works when the calibration record is added/modified, but when a calibration record is deleted, the catalog search fails.

In adapters.py:

@indexer(ICalibratable)
def calduedate_indexer(obj):
    duedate = ICalibrationAccessor(obj).getCalibrationDueDate()
    return duedate

class ICalibrationAccessor(Interface):
    def getCalibrationDueDate():
        """ Get next calibration """

@adapter(ICalibratable)
@implementer(ICalibrationAccessor)
class CalibrationAccessor(object):

    def __init__(self, context):
         object.__setattr__(self, 'context', context)    

    def getCalibrationDueDate(self):
        dates = []
        brains = self.context.getFolderContents({'portal_type':'Calibration'})
        for cal in brains:
            if cal['next_calibration']:
                dates.append(cal['next_calibration'])
        if len(dates) > 0:
            return sorted(dates)[0]
        else:
            return None

In configure.zcml:

<adapter name="calDueDate" factory=".adapters.calduedate_indexer/>
<adapter
    for = "my.product.behaviors.interfaces.ICalibratable"
    provides="my.product.adapters.ICalibrationAccessor"
    factory="my.product.adapters.CalibrationAccessor"/>

Note: The indexer is called automatically when a Calibration is added or deleted, but it needs to be updated manually when modified, so I use an event subscriber on the calibration.

Is there a time when the portal_catalog can not be queried? If so, is there a work around?

It is generally a bad idea to query the catalog why unindexing.
Try replacing self.context.getFolderContents with some other method that actually checks the object you have in your context (self.context.objectValues maybe).

1 Like

Thank you. Changing the approach and using objectValues() doesn't give me any error. However, when I have the indexer return None because there's no next calibration date and I view the Calibratable Type's information through portal_catalog in Zope Interface, the index still has a value, although metadata is None. Can I set the index to None/empty with an indexer?

I think I figured it out. Instead of the indexer returning None, I have it returning '' instead. The calDueDate index and metadata are unset.

If you want an value not to be in the index: do raise AttributeError('some ignored message') instead of returning empty values (or worst: None). This indicates to the index/catalog there is no value for this object for this index.

2 Likes

Thank you very much. Using the 'raise AttributeError('some message") ' is working for me. This would make sense since I'm querying for Dates, and None and empty values such as '' aren't date types.