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))
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, ))
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, ))
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, ))
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
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, ))
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