GitHub PullRequestReviewCommentEvent at 2014-03-26 17:22:28
Repository: django
Actor: alex
Payload: {"comment":{"url":"https://api.github.com/repos/django/django/pulls/comments/10987541","id":10987541,"diff_hunk":"@@ -0,0 +1,184 @@\n+import json\n+import re\n+\n+from django.core import checks\n+from django.db.models import Field, Lookup, Transform, IntegerField\n+from django.utils.module_loading import import_string\n+from django.utils import six\n+from django.utils.functional import cached_property\n+\n+\n+__all__ = ['ArrayField']\n+\n+\n+class ArrayField(Field):\n+    empty_strings_allowed = False\n+\n+    def __init__(self, base_field=None, _base_field_deconstructed=None, **kwargs):\n+        super(ArrayField, self).__init__(**kwargs)\n+        if base_field is not None:\n+            self.base_field = base_field\n+        else:\n+            if _base_field_deconstructed is None:\n+                raise TypeError('base_field is required.')\n+            name, path, args, kwargs = _base_field_deconstructed\n+            self.base_field = import_string(path)(*args, **kwargs)\n+\n+    def check(self, **kwargs):\n+        errors = super(ArrayField, self).check(**kwargs)\n+        if self.base_field.rel:\n+            errors.append(\n+                checks.Error(\n+                    'Base field for array cannot be a related field.',\n+                    hint=None,\n+                    obj=self,\n+                    id='postgres.E002'\n+                )\n+            )\n+        else:\n+            # Remove the field name checks as they are not needed here.\n+            base_errors = self.base_field.check()\n+            if base_errors:\n+                messages = '\\n    '.join('%s (%s)' % (error.msg, error.id) for error in base_errors)\n+                errors.append(\n+                    checks.Error(\n+                        'Base field for array has errors:\\n    %s' % messages,\n+                        hint=None,\n+                        obj=self,\n+                        id='postgres.E001'\n+                    )\n+                )\n+        return errors\n+\n+    def set_attributes_from_name(self, name):\n+        super(ArrayField, self).set_attributes_from_name(name)\n+        self.base_field.set_attributes_from_name(name)\n+\n+    @property\n+    def definition(self):\n+        return 'Array of %s' % self.base_field.definition\n+\n+    def db_type(self, connection):\n+        return self.base_field.db_type(connection) + '[]'\n+\n+    def get_prep_value(self, value):\n+        if isinstance(value, list):\n+            return [self.base_field.get_prep_value(i) for i in value]\n+        return value\n+\n+    def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):\n+        if lookup_type == 'contains':\n+            return [self.get_prep_value(value)]\n+        return super(ArrayField, self).get_db_prep_lookup(lookup_type, value,\n+                connection, prepared=False)\n+\n+    def deconstruct(self):\n+        name, path, args, kwargs = super(ArrayField, self).deconstruct()\n+        kwargs['_base_field_deconstructed'] = self.base_field.deconstruct()\n+        return name, path, args, kwargs\n+\n+    def to_python(self, value):\n+        if isinstance(value, six.string_types):\n+            # Assume we're deserializing\n+            vals = json.loads(value)\n+            value = []\n+            for val in vals:\n+                value.append(self.base_field.to_python(val))\n+        return value\n+\n+    def value_to_string(self, obj):\n+        values = []\n+        vals = self._get_val_from_obj(obj)\n+        base_field = self.base_field\n+\n+        class FakeObj(object):\n+            def __init__(self, value):\n+                setattr(self, base_field.attname, value)\n+\n+        for val in vals:\n+            values.append(base_field.value_to_string(FakeObj(val)))\n+        return json.dumps(values)\n+\n+    def get_transform(self, name):\n+        transform = super(ArrayField, self).get_transform(name)\n+        if transform:\n+            return transform\n+        try:\n+            index = int(name)\n+        except ValueError:\n+            pass\n+        else:\n+            index = index + 1  # postgres uses 1-indexing\n+            return index_transform_factory(index, self.base_field)\n+        if re.match('\\d+_\\d+', name):\n+            start, end = name.split('_')\n+            start = int(start) + 1\n+            end = int(end) + 1\n+            return slice_transform_factory(start, end)\n+\n+\n+class ArrayContainsLookup(Lookup):\n+    lookup_name = 'contains'\n+\n+    def as_sql(self, qn, connection):\n+        lhs, lhs_params = self.process_lhs(qn, connection)\n+        rhs, rhs_params = self.process_rhs(qn, connection)\n+        params = lhs_params + rhs_params\n+        return '%s @> %s' % (lhs, rhs), params\n+\n+\n+ArrayField.register_lookup(ArrayContainsLookup)\n+\n+\n+class ArrayOverlapLookup(Lookup):\n+    lookup_name = 'overlap'\n+\n+    def as_sql(self, qn, connection):\n+        lhs, lhs_params = self.process_lhs(qn, connection)\n+        rhs, rhs_params = self.process_rhs(qn, connection)\n+        params = lhs_params + rhs_params\n+        return '%s && %s' % (lhs, rhs), params\n+\n+\n+ArrayField.register_lookup(ArrayOverlapLookup)\n+\n+\n+class ArrayLenTransform(Transform):\n+    lookup_name = 'len'\n+\n+    @cached_property\n+    def output_type(self):\n+        return IntegerField()\n+\n+    def as_sql(self, qn, connection):\n+        lhs, params = qn.compile(self.lhs)\n+        return 'array_length(%s, 1)' % lhs, params\n+\n+\n+ArrayField.register_lookup(ArrayLenTransform)\n+\n+\n+def index_transform_factory(index, base_field):\n+\n+    class IndexTransform(Transform):","path":"django/contrib/postgres/fields/array.py","position":163,"original_position":163,"commit_id":"fe7201d03a2fd92e83f700ea8cf6ef26bbbf8e9f","original_commit_id":"fe7201d03a2fd92e83f700ea8cf6ef26bbbf8e9f","user":{"login":"alex","id":772,"avatar_url":"https://avatars.githubusercontent.com/u/772?","gravatar_id":"edcdfd5affb524e0f88ec1a00ed3fe5d","url":"https://api.github.com/users/alex","html_url":"https://github.com/alex","followers_url":"https://api.github.com/users/alex/followers","following_url":"https://api.github.com/users/alex/following{/other_user}","gists_url":"https://api.github.com/users/alex/gists{/gist_id}","starred_url":"https://api.github.com/users/alex/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alex/subscriptions","organizations_url":"https://api.github.com/users/alex/orgs","repos_url":"https://api.github.com/users/alex/repos","events_url":"https://api.github.com/users/alex/events{/privacy}","received_events_url":"https://api.github.com/users/alex/received_events","type":"User","site_admin":false},"body":"Please dont' create new classes dynamically for each query like this, `IndexTransform` should be factored out and take some parameter to it's constructor (and then offer an `__call__` or something), same with `SliceTransform`.","created_at":"2014-03-26T17:22:28Z","updated_at":"2014-03-26T17:22:28Z","html_url":"https://github.com/django/django/pull/2485#discussion_r10987541","pull_request_url":"https://api.github.com/repos/django/django/pulls/2485","_links":{"self":{"href":"https://api.github.com/repos/django/django/pulls/comments/10987541"},"html":{"href":"https://github.com/django/django/pull/2485#discussion_r10987541"},"pull_request":{"href":"https://api.github.com/repos/django/django/pulls/2485"}}}}