Commits

Waldemar Kornewald committed ec7af38 Merge

Comments (0)

Files changed (5)

djangotoolbox/db/basecompiler.py

         for entity in self.build_query(fields).fetch(low_mark, high_mark):
             yield self._make_result(entity, fields)
 
-    def _make_result(self, entity, fields):
-        result = []
-        for field in fields:
-            if not field.null and entity.get(field.column,
-                    field.get_default()) is None:
-                raise DatabaseError("Non-nullable field %s can't be None!" % field.name)
-            result.append(self.convert_value_from_db(field.db_type(
-                connection=self.connection), entity.get(field.column, field.get_default())))
-        return result
-
     def has_results(self):
         return self.get_count(check_exists=True)
 
     # ----------------------------------------------
     # Additional NonrelCompiler API
     # ----------------------------------------------
+    def _make_result(self, entity, fields):
+        result = []
+        for field in fields:
+            if not field.null and entity.get(field.column,
+                    field.get_default()) is None:
+                raise DatabaseError("Non-nullable field %s can't be None!" % field.name)
+            result.append(self.convert_value_from_db(field.db_type(
+                connection=self.connection), entity.get(field.column, field.get_default())))
+        return result
+
     def check_query(self):
         if (len([a for a in self.query.alias_map if self.query.alias_refcount[a]]) > 1
                 or self.query.distinct or self.query.extra or self.query.having):

djangotoolbox/dbproxy/api.py

+from django.conf import settings
+from django.db import models
+from django.utils.importlib import import_module
+
+_MODULE_NAMES = getattr(settings, 'DB_INDEX_MODULES', ())
+
+FIELD_INDEXES = {}
+
+def register_index(model, mapping):
+    for name, lookup_types in mapping.items():
+        if isinstance(lookup_types, basestring):
+            lookup_types = (lookup_types,)
+        FIELD_INDEXES.setdefault(model, {})[name] = lookup_types
+        field = model._meta.get_field(name)
+        for lookup_type in lookup_types:
+            index_name = 'idxf_%s_l_%s' % (field.name, lookup_type)
+            index_field = models.CharField(max_length=field.max_length, editable=False, null=True)
+            model.add_to_class(index_name, index_field)
+
+def load_indexes():
+    for name in _MODULE_NAMES:
+        try:
+            import_module(name).FIELD_INDEXES
+        except ImportError:
+            pass

djangotoolbox/dbproxy/base.py

 from django.db import connections
+from django.utils.importlib import import_module
 
 class Proxy(object):
     def __init__(self, target):
-        self.__target = target
-    
+        self._target = target
+
     def __getattr__(self, name):
-        return getattr(self.__target, name)
+        return getattr(self._target, name)
+
+class OperationsProxy(Proxy):
+    compiler_module = __name__.rsplit('.', 1)[0] + '.compiler'
+
+    def __init__(self, *args, **kwargs):
+        super(OperationsProxy, self).__init__(*args, **kwargs)
+        self._cache = {}
+
+    def compiler(self, compiler_name):
+        target = self._target.compiler(compiler_name)
+        if compiler_name not in self._cache:
+            base = getattr(
+                import_module(self.compiler_module), compiler_name)
+            class Compiler(base, target):
+                pass
+            self._cache[compiler_name] = Compiler
+        return self._cache[compiler_name]
 
 class DatabaseWrapper(Proxy):
     def __init__(self, settings_dict, *args, **kwds):
         super(DatabaseWrapper, self).__init__(
-            connections[settings_dict['TARGET_BACKEND']])
+            connections[settings_dict['TARGET']])
+        self.ops = OperationsProxy(self.ops)

djangotoolbox/dbproxy/compiler.py

-from .base import Proxy
+from .api import FIELD_INDEXES
 from django.conf import settings
 from django.db.models.sql import aggregates as sqlaggregates
 from django.db.models.sql.constants import LOOKUP_SEP, MULTI, SINGLE
 from django.db.utils import DatabaseError, IntegrityError
 from django.utils.tree import Node
 
-class SQLCompiler(Proxy):
-    def execute_sql(self, result_type=MULTI):
-        """
-        Handles aggregate/count queries
-        """
-        pass
+LOOKUP_TYPE_CONVERSION = {
+    'iexact': lambda value, _: ('exact', value.lower()),
+}
 
+VALUE_CONVERSION = {
+    'iexact': lambda value: value.lower(),
+}
+
+class SQLCompiler(object):
     def results_iter(self):
-        """
-        Returns an iterator over the results from executing this query.
-        """
-        pass
+        self.convert_filters(self.query.where)
+        return super(SQLCompiler, self).results_iter()
 
-    def has_results(self):
-        pass
+    def convert_filters(self, filters):
+        model = self.query.model
+        for index, child in enumerate(filters.children[:]):
+            if isinstance(child, Node):
+                self.convert_filters(child)
+                continue
 
-class SQLInsertCompiler(Proxy):
+            constraint, lookup_type, annotation, value = child
+            if model in FIELD_INDEXES and constraint.field is not None and \
+                    lookup_type in FIELD_INDEXES[model].get(constraint.field.name, ()):
+                index_name = 'idxf_%s_l_%s' % (constraint.field.name, lookup_type)
+                lookup_type, value = LOOKUP_TYPE_CONVERSION[lookup_type](value, annotation)
+                constraint.field = self.query.get_meta().get_field(index_name)
+                child = (constraint, lookup_type, annotation, value)
+                filters.children[index] = child
+
+class SQLInsertCompiler(object):
     def execute_sql(self, return_id=False):
-        pass
+        position = {}
+        for index, (field, value) in enumerate(self.query.values[:]):
+            position[field.name] = index
 
-class SQLUpdateCompiler(Proxy):
-    def execute_sql(self, result_type=MULTI):
-        pass
+        model = self.query.model
+        for field, value in self.query.values[:]:
+            if field is None or model not in FIELD_INDEXES or \
+                    field.name not in FIELD_INDEXES[model]:
+                continue
+            for lookup_type in FIELD_INDEXES[model][field.name]:
+                index_name = 'idxf_%s_l_%s' % (field.name, lookup_type)
+                index_field = model._meta.get_field(index_name)
+                self.query.values[position[index_name]] = (index_field, VALUE_CONVERSION[lookup_type](value))
+        return super(SQLInsertCompiler, self).execute_sql(return_id=return_id)
 
-class SQLDeleteCompiler(Proxy):
-    def execute_sql(self, result_type=MULTI):
-        pass
+class SQLUpdateCompiler(object):
+    pass
+
+class SQLDeleteCompiler(object):
+    pass

djangotoolbox/test.py

         stderr = sys.stderr
 
         def extend_error(errors):
-            captured_stdout = sys.stdout.getvalue()
-            captured_stderr = sys.stderr.getvalue()
+            try:
+                captured_stdout = sys.stdout.getvalue()
+                captured_stderr = sys.stderr.getvalue()
+            except AttributeError:
+                captured_stdout = captured_stderr = ''
             sys.stdout = stdout
             sys.stderr = stderr
             t, e = errors[-1]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.