Example #1
0
    def test_no_type_error(self):
        ''' Check that on Python 3.6 we do not get a TypeError when trying
        to query an index with a key that has an invalid type
        '''
        index = self._makeOne('counter')

        class Dummy(object):
            id = 1
            counter = 'test'

        obj = Dummy()
        index.index_object(obj.id, obj)

        # With the right query we can find the object
        query = IndexQuery({'counter': 'test'}, 'counter')
        res = index.query_index(query)
        self.assertListEqual(list(res), [1])

        # If the type is not the expected one we cannot
        query = IndexQuery({'counter': None}, 'counter')
        res = index.query_index(query)
        self.assertListEqual(list(res), [])

        query = IndexQuery({'counter': 42}, 'counter')
        res = index.query_index(query)
        self.assertListEqual(list(res), [])
 def _apply_index(self, request, resultset=None):
     record = IndexQuery(request, self.id, self.query_options,
                         self.operators, self.useOperator)
     if record.keys is None:
         return None
     return (self.query_index(record, resultset=resultset),
             (self._since_field, self._until_field))
Example #3
0
 def _apply_index(self, request, resultset=None):
     """ hook for (Z)Catalog
         'request' --  mapping type (usually {"path": "..." }
          additionaly a parameter "path_level" might be passed
          to specify the level (see search())
     """
     record = IndexQuery(request, self.id, self.query_options)
     if record.keys is None:
         return None
     return (self.query_index(record), (self.id, ))
Example #4
0
    def _apply_index(self, request, resultset=None):
        """Apply the index to query parameters given in the request arg.

        If the query does not match the index, return None, otherwise
        return a tuple of (result, used_attributes), where used_attributes
        is again a tuple with the names of all used data fields.
        """
        record = IndexQuery(request, self.id, self.query_options,
                            self.operators, self.useOperator)
        if record.keys is None:
            return None
        return (self.query_index(record, resultset=resultset), (self.id, ))
Example #5
0
    def _apply_index(self, request, resultset=None):
        """Apply the index to query parameters given in the request arg.

        If the query does not match the index, return None, otherwise
        return a tuple of (result, used_attributes), where used_attributes
        is again a tuple with the names of all used data fields.

        If not `None`, the resultset argument
        indicates that the search result is relevant only on this set,
        i.e. everything outside resultset is of no importance.
        The index can use this information for optimizations.
        """
        record = IndexQuery(request, self.id, self.query_options,
                            self.operators, self.useOperator)
        if record.keys is None:
            return None
        return (self.query_index(record, resultset=resultset), (self.id, ))
Example #6
0
    def _search_index(self, cr, index_id, query, rs):
        cr.start_split(index_id)

        index_rs = None
        index = self.getIndex(index_id)
        limit_result = ILimitedResultIndex.providedBy(index)

        if IQueryIndex.providedBy(index):
            index_query = IndexQuery(query, index.id, index.query_options,
                                     index.operators, index.useOperator)
            if index_query.keys is not None:
                index_rs = index.query_index(index_query, rs)
        else:
            if limit_result:
                index_result = index._apply_index(query, rs)
            else:
                index_result = index._apply_index(query)

            # Parse (resultset, used_attributes) index return value.
            if index_result:
                index_rs, _ = index_result

        if not index_rs:
            # Short circuit if empty index result.
            rs = None
        else:
            # Provide detailed info about the pure intersection time.
            intersect_id = index_id + '#intersection'
            cr.start_split(intersect_id)
            # weightedIntersection preserves the values from any mappings
            # we get, as some indexes don't return simple sets.
            if hasattr(rs, 'items') or hasattr(index_rs, 'items'):
                _, rs = weightedIntersection(rs, index_rs)
            else:
                rs = intersection(rs, index_rs)

            cr.stop_split(intersect_id)

        # Consider the time it takes to intersect the index result
        # with the total result set to be part of the index time.
        cr.stop_split(index_id, result=index_rs, limit=limit_result)

        return rs
Example #7
0
 def _apply_index(self, request):
     record = IndexQuery(request, self.id, self.query_options,
                         self.operators, self.useOperator)
     if record.keys is None:
         return None
     return (self.query_index(record), (self.id, ))
Example #8
0
    def make_query(self, query):
        """ optimize the query for supported index names """

        try:
            zc = aq_parent(aq_parent(self))
            skip = zc.getProperty('skip_compositeindex', False)
            if skip:
                LOG.debug(
                    '%(context)s: skip composite query build '
                    'for %(zcatalog)r',
                    dict(context=self.__class__.__name__, zcatalog=zc))
                return query
        except AttributeError:
            pass

        if len(self) == 0:
            return query

        cquery = query.copy()
        components = self.getIndexComponents()

        # collect components matching query attributes
        # and check them for completeness
        c_records = []
        for c in components:
            query_options = QUERY_OPTIONS[c.meta_type]
            query_operators = QUERY_OPERATORS[c.meta_type]
            rec = IndexQuery(query, c.id, query_options, query_operators[0],
                             query_operators[1])

            # not supported: 'not' parameter
            not_parm = rec.get('not', None)
            if not rec.keys and not_parm:
                continue

            # not supported: 'and' operator
            if rec.keys and rec.operator == 'and':
                continue

            # continue if no keys in query were set
            if rec.keys is None:
                continue

            # convert rec keys to int for BooleanIndex
            if c.meta_type == 'BooleanIndex':
                rec.keys = [int(bool(v)) for v in rec.keys[:]]

            c_records.append((c.id, rec))

        # return if less than MIN_COMPONENTS query attributes were caught
        if len(c_records) < MIN_COMPONENTS:
            return query

        kw_list = []
        for c_id, rec in c_records:
            kw = rec.keys
            if not kw:
                continue
            if isinstance(kw, list):
                kw = tuple(kw)
            elif not isinstance(kw, tuple):
                kw = (kw, )
            kw = tuple([(c_id, k) for k in kw])
            kw_list.append(kw)

        # permute keyword list
        records = tuple(product(*kw_list))

        # substitute matching query attributes as composite index
        cquery.update({self.id: {'query': records}})

        # delete original matching query attributes from query
        for c_id, rec in c_records:
            if c_id in cquery:
                del cquery[c_id]

        return cquery
    def make_query(self, query):
        """ optimize the query for supported index names """

        try:
            zc = aq_parent(aq_parent(self))
            skip = zc.getProperty('skip_compositeindex', False)
            if skip:
                LOG.debug('%(context)s: skip composite query build '
                          'for %(zcatalog)r', dict(
                              context=self.__class__.__name__,
                              zcatalog=zc))
                return query
        except AttributeError:
            pass

        if len(self) == 0:
            return query

        cquery = query.copy()
        components = self.getIndexComponents()

        # collect components matching query attributes
        # and check them for completeness
        c_records = []

        # component ids containing 'not' operator
        not_cids = []

        for c in components:
            query_options = QUERY_OPTIONS[c.meta_type]
            query_operators = QUERY_OPERATORS[c.meta_type]
            rec = IndexQuery(query, c.id, query_options,
                             query_operators[0], query_operators[1])
            opr = None

            # not supported: 'range' parameter
            range_parm = rec.get('range', None)
            if range_parm:
                opr = 'range'
            if rec.get('usage', None):
                # see if any usage params are sent to field
                opr = rec.usage.lower().split(':')
            if opr == 'range':
                continue

            # not supported: 'and' operator
            if rec.keys and rec.operator == 'and':
                continue

            # continue if no keys in query were set
            if rec.keys is None:
                continue

            # convert rec keys to int for BooleanIndex
            if c.meta_type == 'BooleanIndex':
                rec.keys = [int(bool(v)) for v in rec.keys[:]]

            # rec with 'not' parameter
            not_parm = rec.get('not', None)
            if not_parm:
                # not supported: 'pure not'
                if len(rec.keys) == 0:
                    continue
                not_cids.append(c.id)
                if c.meta_type == 'BooleanIndex':
                    not_parm = [int(bool(v)) for v in not_parm[:]]
                    rec.set('not', not_parm)

            c_records.append((c.id, rec))

        # return if less than MIN_COMPONENTS query attributes were caught
        if len(c_records) < MIN_COMPONENTS:
            return query

        records = ()
        kw_list = collect(c_records)
        # permute keyword list
        records = tuple(product(*kw_list))

        not_records = set()
        for c_id in not_cids:
            kw_list = collect(c_records, not_cid=c_id)
            if kw_list:
                not_records.update(product(*kw_list))
        # permute keyword list for 'not' operator
        not_records = tuple(not_records)

        # substitute matching query attributes as composite index
        if records and not_records:
            cquery.update({self.id: {'query': records, 'not': not_records}})
        elif records:
            cquery.update({self.id: {'query': records}})
        elif not_records:
            cquery.update({self.id: {'not': not_records}})

        # delete original matching query attributes from query
        for c_id, rec in c_records:
            if c_id in cquery:
                del cquery[c_id]

        return cquery
    def make_query(self, query):
        """ optimize the query for supported index names """

        try:
            zc = aq_parent(aq_parent(self))
            skip = zc.getProperty('skip_compositeindex', False)
            if skip:
                LOG.debug(
                    '%(context)s: skip composite query build '
                    'for %(zcatalog)r',
                    dict(context=self.__class__.__name__, zcatalog=zc))
                return query
        except AttributeError:
            pass

        if len(self) == 0:
            return query

        cquery = query.copy()
        components = self.getIndexComponents()

        # collect components matching query attributes
        # and check them for completeness
        c_records = []

        # component ids containing 'not' operator
        not_cids = []

        for c in components:
            query_options = QUERY_OPTIONS[c.meta_type]
            query_operators = QUERY_OPERATORS[c.meta_type]
            rec = IndexQuery(query, c.id, query_options, query_operators[0],
                             query_operators[1])
            opr = None

            # not supported: 'range' parameter
            range_parm = rec.get('range', None)
            if range_parm:
                opr = 'range'
            if rec.get('usage', None):
                # see if any usage params are sent to field
                opr = rec.usage.lower().split(':')
            if opr == 'range':
                continue

            # not supported: 'and' operator
            if rec.keys and rec.operator == 'and':
                continue

            # continue if no keys in query were set
            if rec.keys is None:
                continue

            # convert rec keys to int for BooleanIndex
            if c.meta_type == 'BooleanIndex':
                rec.keys = [int(bool(v)) for v in rec.keys[:]]

            # rec with 'not' parameter
            not_parm = rec.get('not', None)
            if not_parm:
                # not supported: 'pure not'
                if len(rec.keys) == 0:
                    continue
                not_cids.append(c.id)
                if c.meta_type == 'BooleanIndex':
                    not_parm = [int(bool(v)) for v in not_parm[:]]
                    rec.set('not', not_parm)

            c_records.append((c.id, rec))

        # return if less than MIN_COMPONENTS query attributes were caught
        if len(c_records) < MIN_COMPONENTS:
            return query

        records = ()
        kw_list = collect(c_records)
        # permute keyword list
        records = tuple(product(*kw_list))

        not_records = set()
        for c_id in not_cids:
            kw_list = collect(c_records, not_cid=c_id)
            if kw_list:
                not_records.update(product(*kw_list))
        # permute keyword list for 'not' operator
        not_records = tuple(not_records)

        # substitute matching query attributes as composite index
        if records and not_records:
            cquery.update({self.id: {'query': records, 'not': not_records}})
        elif records:
            cquery.update({self.id: {'query': records}})
        elif not_records:
            cquery.update({self.id: {'not': not_records}})

        # delete original matching query attributes from query
        for c_id, rec in c_records:
            if c_id in cquery:
                del cquery[c_id]

        return cquery