def _find_non_wildcards(self, values): """Check if this should be a wildcard match. Further, this will raise an exception if the syntax is improperly defined. :return: The offset of the last value we need to match against. """ if len(values) != len(self._definition): raise errors.InvalidValueForIndex() is_wildcard = False last = 0 for idx, val in enumerate(values): if val.endswith('*'): if val != '*': # We have an 'x*' style wildcard if is_wildcard: # We were already in wildcard mode, so this is invalid raise errors.InvalidGlobbing last = idx + 1 is_wildcard = True else: if is_wildcard: # We were in wildcard mode, we can't follow that with # non-wildcard raise errors.InvalidGlobbing last = idx + 1 if not is_wildcard: return -1 return last
def get_from_index(self, index_name, *key_values): definition = self._get_index_definition(index_name) if len(key_values) != len(definition): raise errors.InvalidValueForIndex() statement, args = self._format_query(definition, key_values) c = self._db_handle.cursor() try: c.execute(statement, tuple(args)) except dbapi2.OperationalError, e: raise dbapi2.OperationalError(str(e) + '\nstatement: %s\nargs: %s\n' % (statement, args))
def get_count_from_index(self, index_name, *key_values): """ Returns the count for a given combination of index_name and key values. Extension method made from similar methods in u1db version 13.09 :param index_name: The index to query :type index_name: str :param key_values: values to match. eg, if you have an index with 3 fields then you would have: get_from_index(index_name, val1, val2, val3) :type key_values: tuple :return: count. :rtype: int """ c = self._db_handle.cursor() definition = self._get_index_definition(index_name) if len(key_values) != len(definition): raise u1db_errors.InvalidValueForIndex() tables = ["document_fields d%d" % i for i in range(len(definition))] novalue_where = [ "d.doc_id = d%d.doc_id" " AND d%d.field_name = ?" % (i, i) for i in range(len(definition)) ] exact_where = [ novalue_where[i] + (" AND d%d.value = ?" % (i, )) for i in range(len(definition)) ] args = [] where = [] for idx, (field, value) in enumerate(zip(definition, key_values)): args.append(field) where.append(exact_where[idx]) args.append(value) tables = ["document_fields d%d" % i for i in range(len(definition))] statement = ("SELECT COUNT(*) FROM document d, %s WHERE %s " % ( ', '.join(tables), ' AND '.join(where), )) try: c.execute(statement, tuple(args)) except dbapi2.OperationalError, e: raise dbapi2.OperationalError( str(e) + '\nstatement: %s\nargs: %s\n' % (statement, args))
def _format_range_query(self, definition, start_value, end_value): tables = ["document_fields d%d" % i for i in range(len(definition))] novalue_where = [ "d.doc_id = d%d.doc_id AND d%d.field_name = ?" % (i, i) for i in range(len(definition))] wildcard_where = [ novalue_where[i] + (" AND d%d.value NOT NULL" % (i,)) for i in range(len(definition))] like_where = [ novalue_where[i] + ( " AND (d%d.value < ? OR d%d.value GLOB ?)" % (i, i)) for i in range(len(definition))] range_where_lower = [ novalue_where[i] + (" AND d%d.value >= ?" % (i,)) for i in range(len(definition))] range_where_upper = [ novalue_where[i] + (" AND d%d.value <= ?" % (i,)) for i in range(len(definition))] args = [] where = [] if start_value: if isinstance(start_value, basestring): start_value = (start_value,) if len(start_value) != len(definition): raise errors.InvalidValueForIndex() is_wildcard = False for idx, (field, value) in enumerate(zip(definition, start_value)): args.append(field) if value.endswith('*'): if value == '*': where.append(wildcard_where[idx]) else: # This is a glob match if is_wildcard: # We can't have a partial wildcard following # another wildcard raise errors.InvalidGlobbing where.append(range_where_lower[idx]) args.append(self._strip_glob(value)) is_wildcard = True else: if is_wildcard: raise errors.InvalidGlobbing where.append(range_where_lower[idx]) args.append(value) if end_value: if isinstance(end_value, basestring): end_value = (end_value,) if len(end_value) != len(definition): raise errors.InvalidValueForIndex() is_wildcard = False for idx, (field, value) in enumerate(zip(definition, end_value)): args.append(field) if value.endswith('*'): if value == '*': where.append(wildcard_where[idx]) else: # This is a glob match if is_wildcard: # We can't have a partial wildcard following # another wildcard raise errors.InvalidGlobbing where.append(like_where[idx]) args.append(self._strip_glob(value)) args.append(value) is_wildcard = True else: if is_wildcard: raise errors.InvalidGlobbing where.append(range_where_upper[idx]) args.append(value) statement = ( "SELECT d.doc_id, d.doc_rev, d.content, count(c.doc_rev) FROM " "document d, %s LEFT OUTER JOIN conflicts c ON c.doc_id = " "d.doc_id WHERE %s GROUP BY d.doc_id, d.doc_rev, d.content ORDER " "BY %s;" % (', '.join(tables), ' AND '.join(where), ', '.join( ['d%d.value' % i for i in range(len(definition))]))) return statement, args
def get_range_from_index(self, index_name, start_value=None, end_value=None): """Return all documents with key values in the specified range.""" definition = self._get_index_definition(index_name) tables = ["document_fields d%d" % i for i in range(len(definition))] novalue_where = [ "d.doc_id = d%d.doc_id AND d%d.field_name = ?" % (i, i) for i in range(len(definition)) ] wildcard_where = [ novalue_where[i] + (" AND d%d.value NOT NULL" % (i, )) for i in range(len(definition)) ] like_where = [ novalue_where[i] + (" AND (d%d.value < ? OR d%d.value LIKE ? ESCAPE '.')" % (i, i)) for i in range(len(definition)) ] range_where_lower = [ novalue_where[i] + (" AND d%d.value >= ?" % (i, )) for i in range(len(definition)) ] range_where_upper = [ novalue_where[i] + (" AND d%d.value <= ?" % (i, )) for i in range(len(definition)) ] args = [] where = [] if start_value: if isinstance(start_value, basestring): start_value = (start_value, ) if len(start_value) != len(definition): raise errors.InvalidValueForIndex() is_wildcard = False for idx, (field, value) in enumerate(zip(definition, start_value)): args.append(field) if value.endswith('*'): if value == '*': where.append(wildcard_where[idx]) else: # This is a glob match if is_wildcard: # We can't have a partial wildcard following # another wildcard raise errors.InvalidGlobbing where.append(range_where_lower[idx]) args.append(self._strip_glob(value)) is_wildcard = True else: if is_wildcard: raise errors.InvalidGlobbing where.append(range_where_lower[idx]) args.append(value) if end_value: if isinstance(end_value, basestring): end_value = (end_value, ) if len(end_value) != len(definition): raise errors.InvalidValueForIndex() is_wildcard = False for idx, (field, value) in enumerate(zip(definition, end_value)): args.append(field) if value.endswith('*'): if value == '*': where.append(wildcard_where[idx]) else: # This is a glob match if is_wildcard: # We can't have a partial wildcard following # another wildcard raise errors.InvalidGlobbing where.append(like_where[idx]) args.append(self._strip_glob(value)) args.append(self._transform_glob(value)) is_wildcard = True else: if is_wildcard: raise errors.InvalidGlobbing where.append(range_where_upper[idx]) args.append(value) statement = ( "SELECT d.doc_id, d.doc_rev, d.content FROM document d, %s " "WHERE %s ORDER BY %s;" % (', '.join(tables), ' AND '.join(where), ', '.join( ['d%d.value' % i for i in range(len(definition))]))) c = self._db_handle.cursor() try: c.execute(statement, tuple(args)) except dbapi2.OperationalError, e: raise dbapi2.OperationalError( str(e) + '\nstatement: %s\nargs: %s\n' % (statement, args))
def get_from_index(self, index_name, *key_values): definition = self._get_index_definition(index_name) # First, build the definition. We join the document_fields table # against itself, as many times as the 'width' of our definition. # We then do a query for each key_value, one-at-a-time. # Note: All of these strings are static, we could cache them, etc. tables = ["document_fields d%d" % i for i in range(len(definition))] novalue_where = [ "d.doc_id = d%d.doc_id" " AND d%d.field_name = ?" % (i, i) for i in range(len(definition)) ] wildcard_where = [ novalue_where[i] + (" AND d%d.value NOT NULL" % (i, )) for i in range(len(definition)) ] exact_where = [ novalue_where[i] + (" AND d%d.value = ?" % (i, )) for i in range(len(definition)) ] like_where = [ novalue_where[i] + (" AND d%d.value LIKE ? ESCAPE '.'" % (i, )) for i in range(len(definition)) ] c = self._db_handle.cursor() is_wildcard = False # Merge the lists together, so that: # [field1, field2, field3], [val1, val2, val3] # Becomes: # (field1, val1, field2, val2, field3, val3) args = [] where = [] if len(key_values) != len(definition): raise errors.InvalidValueForIndex() for idx, (field, value) in enumerate(zip(definition, key_values)): args.append(field) if value.endswith('*'): if value == '*': where.append(wildcard_where[idx]) else: # This is a glob match if is_wildcard: # We can't have a partial wildcard following # another wildcard raise errors.InvalidGlobbing where.append(like_where[idx]) args.append(self._transform_glob(value)) is_wildcard = True else: if is_wildcard: raise errors.InvalidGlobbing where.append(exact_where[idx]) args.append(value) statement = ( "SELECT d.doc_id, d.doc_rev, d.content FROM document d, %s " "WHERE %s ORDER BY %s;" % (', '.join(tables), ' AND '.join(where), ', '.join( ['d%d.value' % i for i in range(len(definition))]))) try: c.execute(statement, tuple(args)) except dbapi2.OperationalError, e: raise dbapi2.OperationalError( str(e) + '\nstatement: %s\nargs: %s\n' % (statement, args))