{"action":"created","comment":{"url":"https://api.github.com/repos/django/django/pulls/comments/86701639","pull_request_review_id":7346033,"id":86701639,"diff_hunk":"@@ -372,77 +376,87 @@ def as_sql(self, compiler, connection):\n             lhs_output = self.lhs.output_field\n         except FieldError:\n             lhs_output = None\n+\n         try:\n             rhs_output = self.rhs.output_field\n         except FieldError:\n             rhs_output = None\n+\n+        # for databases that don't do temporal interval types, skip the\n+        # dispatcher and force resolution to DurationExpression\n         if (not connection.features.has_native_duration_field and\n                 ((lhs_output and lhs_output.get_internal_type() == 'DurationField') or\n                  (rhs_output and rhs_output.get_internal_type() == 'DurationField'))):\n+            from .operators import DurationExpression\n             return DurationExpression(self.lhs, self.connector, self.rhs).as_sql(compiler, connection)\n-        if (lhs_output and rhs_output and self.connector == self.SUB and\n-            lhs_output.get_internal_type() in {'DateField', 'DateTimeField', 'TimeField'} and\n-                lhs_output.get_internal_type() == lhs_output.get_internal_type()):\n-            return TemporalSubtraction(self.lhs, self.rhs).as_sql(compiler, connection)\n-        expressions = []\n-        expression_params = []\n-        sql, params = compiler.compile(self.lhs)\n-        expressions.append(sql)\n-        expression_params.extend(params)\n-        sql, params = compiler.compile(self.rhs)\n-        expressions.append(sql)\n-        expression_params.extend(params)\n-        # order of precedence\n-        expression_wrapper = '(%s)'\n-        sql = connection.ops.combine_expression(self.connector, expressions)\n-        return expression_wrapper % sql, expression_params\n \n-    def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):\n-        c = self.copy()\n-        c.is_summary = summarize\n-        c.lhs = c.lhs.resolve_expression(query, allow_joins, reuse, summarize, for_save)\n-        c.rhs = c.rhs.resolve_expression(query, allow_joins, reuse, summarize, for_save)\n-        return c\n+        if lhs_output or rhs_output:\n+            dispatchers = (self.expression_dispatchers.get(self.connector),\n+                           self.expression_dispatchers.get(CombinedExpression.ANY))\n \n+            for dispatcher in filter(bool, dispatchers):\n+                try:\n+                    klass = dispatcher(lhs_output or fields.Field(), rhs_output or fields.Field())\n \n-class DurationExpression(CombinedExpression):\n-    def compile(self, side, compiler, connection):\n-        if not isinstance(side, DurationValue):\n-            try:\n-                output = side.output_field\n-            except FieldError:\n-                pass\n-            else:\n-                if output.get_internal_type() == 'DurationField':\n-                    sql, params = compiler.compile(side)\n-                    return connection.ops.format_for_duration_arithmetic(sql), params\n-        return compiler.compile(side)\n+                    # avoid recursion in case CombinedExpression maps to another\n+                    # CombinedExpression, but with a different connector\n+                    if type(self) != klass:\n+                        try:\n+                            output_field = self._output_field_or_none\n+                        except FieldError:\n+                            output_field = None\n+\n+                        expression = klass(self.lhs, self.connector, self.rhs, output_field=output_field)\n+                        return compiler.compile(expression)","path":"django/db/models/expressions.py","position":100,"original_position":100,"commit_id":"8cafcb8f0a8b2d2b9e0f63aac21a307a8b9d113c","original_commit_id":"8cafcb8f0a8b2d2b9e0f63aac21a307a8b9d113c","user":{"login":"charettes","id":9293,"avatar_url":"https://avatars.githubusercontent.com/u/9293?v=3","gravatar_id":"","url":"https://api.github.com/users/charettes","html_url":"https://github.com/charettes","followers_url":"https://api.github.com/users/charettes/followers","following_url":"https://api.github.com/users/charettes/following{/other_user}","gists_url":"https://api.github.com/users/charettes/gists{/gist_id}","starred_url":"https://api.github.com/users/charettes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/charettes/subscriptions","organizations_url":"https://api.github.com/users/charettes/orgs","repos_url":"https://api.github.com/users/charettes/repos","events_url":"https://api.github.com/users/charettes/events{/privacy}","received_events_url":"https://api.github.com/users/charettes/received_events","type":"User","site_admin":false},"body":"Keep the `try` body to a minimum by only including the code that could raise the expected `NotImplementedError` exception. Use an `else` branch if necessary.","created_at":"2016-11-07T00:39:52Z","updated_at":"2016-11-07T00:39:52Z","html_url":"https://github.com/django/django/pull/6395#discussion_r86701639","pull_request_url":"https://api.github.com/repos/django/django/pulls/6395","_links":{"self":{"href":"https://api.github.com/repos/django/django/pulls/comments/86701639"},"html":{"href":"https://github.com/django/django/pull/6395#discussion_r86701639"},"pull_request":{"href":"https://api.github.com/repos/django/django/pulls/6395"}}},"pull_request":{"url":"https://api.github.com/repos/django/django/pulls/6395","id":65065393,"html_url":"https://github.com/django/django/pull/6395","diff_url":"https://github.com/django/django/pull/6395.diff","patch_url":"https://github.com/django/django/pull/6395.patch","issue_url":"https://api.github.com/repos/django/django/issues/6395","number":6395,"state":"open","locked":false,"title":"Fixed #26355 -- Added API to register different expressions for operator/field combo.","user":{"login":"mrzechonek","id":1334449,"avatar_url":"https://avatars.githubusercontent.com/u/1334449?v=3","gravatar_id":"","url":"https://api.github.com/users/mrzechonek","html_url":"https://github.com/mrzechonek","followers_url":"https://api.github.com/users/mrzechonek/followers","following_url":"https://api.github.com/users/mrzechonek/following{/other_user}","gists_url":"https://api.github.com/users/mrzechonek/gists{/gist_id}","starred_url":"https://api.github.com/users/mrzechonek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrzechonek/subscriptions","organizations_url":"https://api.github.com/users/mrzechonek/orgs","repos_url":"https://api.github.com/users/mrzechonek/repos","events_url":"https://api.github.com/users/mrzechonek/events{/privacy}","received_events_url":"https://api.github.com/users/mrzechonek/received_events","type":"User","site_admin":false},"body":"The idea is to register expression class in `CombinedExpression` lookup\ndict so that it can construct i.e. a `Func` when combining two sides with\nPython's `+` operator.\n","created_at":"2016-04-03T11:03:25Z","updated_at":"2016-11-07T00:39:52Z","closed_at":null,"merged_at":null,"merge_commit_sha":"702cf97047d999d6e7ad3c046a4e7bbb26f8398f","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/django/django/pulls/6395/commits","review_comments_url":"https://api.github.com/repos/django/django/pulls/6395/comments","review_comment_url":"https://api.github.com/repos/django/django/pulls/comments{/number}","comments_url":"https://api.github.com/repos/django/django/issues/6395/comments","statuses_url":"https://api.github.com/repos/django/django/statuses/8cafcb8f0a8b2d2b9e0f63aac21a307a8b9d113c","head":{"label":"mrzechonek:combinable_expreessions","ref":"combinable_expreessions","sha":"8cafcb8f0a8b2d2b9e0f63aac21a307a8b9d113c","user":{"login":"mrzechonek","id":1334449,"avatar_url":"https://avatars.githubusercontent.com/u/1334449?v=3","gravatar_id":"","url":"https://api.github.com/users/mrzechonek","html_url":"https://github.com/mrzechonek","followers_url":"https://api.github.com/users/mrzechonek/followers","following_url":"https://api.github.com/users/mrzechonek/following{/other_user}","gists_url":"https://api.github.com/users/mrzechonek/gists{/gist_id}","starred_url":"https://api.github.com/users/mrzechonek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrzechonek/subscriptions","organizations_url":"https://api.github.com/users/mrzechonek/orgs","repos_url":"https://api.github.com/users/mrzechonek/repos","events_url":"https://api.github.com/users/mrzechonek/events{/privacy}","received_events_url":"https://api.github.com/users/mrzechonek/received_events","type":"User","site_admin":false},"repo":{"id":55297548,"name":"django","full_name":"mrzechonek/django","owner":{"login":"mrzechonek","id":1334449,"avatar_url":"https://avatars.githubusercontent.com/u/1334449?v=3","gravatar_id":"","url":"https://api.github.com/users/mrzechonek","html_url":"https://github.com/mrzechonek","followers_url":"https://api.github.com/users/mrzechonek/followers","following_url":"https://api.github.com/users/mrzechonek/following{/other_user}","gists_url":"https://api.github.com/users/mrzechonek/gists{/gist_id}","starred_url":"https://api.github.com/users/mrzechonek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrzechonek/subscriptions","organizations_url":"https://api.github.com/users/mrzechonek/orgs","repos_url":"https://api.github.com/users/mrzechonek/repos","events_url":"https://api.github.com/users/mrzechonek/events{/privacy}","received_events_url":"https://api.github.com/users/mrzechonek/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mrzechonek/django","description":"The Web framework for perfectionists with deadlines.","fork":true,"url":"https://api.github.com/repos/mrzechonek/django","forks_url":"https://api.github.com/repos/mrzechonek/django/forks","keys_url":"https://api.github.com/repos/mrzechonek/django/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mrzechonek/django/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mrzechonek/django/teams","hooks_url":"https://api.github.com/repos/mrzechonek/django/hooks","issue_events_url":"https://api.github.com/repos/mrzechonek/django/issues/events{/number}","events_url":"https://api.github.com/repos/mrzechonek/django/events","assignees_url":"https://api.github.com/repos/mrzechonek/django/assignees{/user}","branches_url":"https://api.github.com/repos/mrzechonek/django/branches{/branch}","tags_url":"https://api.github.com/repos/mrzechonek/django/tags","blobs_url":"https://api.github.com/repos/mrzechonek/django/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mrzechonek/django/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mrzechonek/django/git/refs{/sha}","trees_url":"https://api.github.com/repos/mrzechonek/django/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mrzechonek/django/statuses/{sha}","languages_url":"https://api.github.com/repos/mrzechonek/django/languages","stargazers_url":"https://api.github.com/repos/mrzechonek/django/stargazers","contributors_url":"https://api.github.com/repos/mrzechonek/django/contributors","subscribers_url":"https://api.github.com/repos/mrzechonek/django/subscribers","subscription_url":"https://api.github.com/repos/mrzechonek/django/subscription","commits_url":"https://api.github.com/repos/mrzechonek/django/commits{/sha}","git_commits_url":"https://api.github.com/repos/mrzechonek/django/git/commits{/sha}","comments_url":"https://api.github.com/repos/mrzechonek/django/comments{/number}","issue_comment_url":"https://api.github.com/repos/mrzechonek/django/issues/comments{/number}","contents_url":"https://api.github.com/repos/mrzechonek/django/contents/{+path}","compare_url":"https://api.github.com/repos/mrzechonek/django/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mrzechonek/django/merges","archive_url":"https://api.github.com/repos/mrzechonek/django/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mrzechonek/django/downloads","issues_url":"https://api.github.com/repos/mrzechonek/django/issues{/number}","pulls_url":"https://api.github.com/repos/mrzechonek/django/pulls{/number}","milestones_url":"https://api.github.com/repos/mrzechonek/django/milestones{/number}","notifications_url":"https://api.github.com/repos/mrzechonek/django/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mrzechonek/django/labels{/name}","releases_url":"https://api.github.com/repos/mrzechonek/django/releases{/id}","deployments_url":"https://api.github.com/repos/mrzechonek/django/deployments","created_at":"2016-04-02T14:01:30Z","updated_at":"2016-04-02T14:01:47Z","pushed_at":"2016-11-06T10:47:35Z","git_url":"git://github.com/mrzechonek/django.git","ssh_url":"git@github.com:mrzechonek/django.git","clone_url":"https://github.com/mrzechonek/django.git","svn_url":"https://github.com/mrzechonek/django","homepage":"https://www.djangoproject.com/","size":149468,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"django:master","ref":"master","sha":"f46a838efc9482c9c7834a83a152b57a56888fff","user":{"login":"django","id":27804,"avatar_url":"https://avatars.githubusercontent.com/u/27804?v=3","gravatar_id":"","url":"https://api.github.com/users/django","html_url":"https://github.com/django","followers_url":"https://api.github.com/users/django/followers","following_url":"https://api.github.com/users/django/following{/other_user}","gists_url":"https://api.github.com/users/django/gists{/gist_id}","starred_url":"https://api.github.com/users/django/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/django/subscriptions","organizations_url":"https://api.github.com/users/django/orgs","repos_url":"https://api.github.com/users/django/repos","events_url":"https://api.github.com/users/django/events{/privacy}","received_events_url":"https://api.github.com/users/django/received_events","type":"Organization","site_admin":false},"repo":{"id":4164482,"name":"django","full_name":"django/django","owner":{"login":"django","id":27804,"avatar_url":"https://avatars.githubusercontent.com/u/27804?v=3","gravatar_id":"","url":"https://api.github.com/users/django","html_url":"https://github.com/django","followers_url":"https://api.github.com/users/django/followers","following_url":"https://api.github.com/users/django/following{/other_user}","gists_url":"https://api.github.com/users/django/gists{/gist_id}","starred_url":"https://api.github.com/users/django/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/django/subscriptions","organizations_url":"https://api.github.com/users/django/orgs","repos_url":"https://api.github.com/users/django/repos","events_url":"https://api.github.com/users/django/events{/privacy}","received_events_url":"https://api.github.com/users/django/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/django/django","description":"The Web framework for perfectionists with deadlines.","fork":false,"url":"https://api.github.com/repos/django/django","forks_url":"https://api.github.com/repos/django/django/forks","keys_url":"https://api.github.com/repos/django/django/keys{/key_id}","collaborators_url":"https://api.github.com/repos/django/django/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/django/django/teams","hooks_url":"https://api.github.com/repos/django/django/hooks","issue_events_url":"https://api.github.com/repos/django/django/issues/events{/number}","events_url":"https://api.github.com/repos/django/django/events","assignees_url":"https://api.github.com/repos/django/django/assignees{/user}","branches_url":"https://api.github.com/repos/django/django/branches{/branch}","tags_url":"https://api.github.com/repos/django/django/tags","blobs_url":"https://api.github.com/repos/django/django/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/django/django/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/django/django/git/refs{/sha}","trees_url":"https://api.github.com/repos/django/django/git/trees{/sha}","statuses_url":"https://api.github.com/repos/django/django/statuses/{sha}","languages_url":"https://api.github.com/repos/django/django/languages","stargazers_url":"https://api.github.com/repos/django/django/stargazers","contributors_url":"https://api.github.com/repos/django/django/contributors","subscribers_url":"https://api.github.com/repos/django/django/subscribers","subscription_url":"https://api.github.com/repos/django/django/subscription","commits_url":"https://api.github.com/repos/django/django/commits{/sha}","git_commits_url":"https://api.github.com/repos/django/django/git/commits{/sha}","comments_url":"https://api.github.com/repos/django/django/comments{/number}","issue_comment_url":"https://api.github.com/repos/django/django/issues/comments{/number}","contents_url":"https://api.github.com/repos/django/django/contents/{+path}","compare_url":"https://api.github.com/repos/django/django/compare/{base}...{head}","merges_url":"https://api.github.com/repos/django/django/merges","archive_url":"https://api.github.com/repos/django/django/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/django/django/downloads","issues_url":"https://api.github.com/repos/django/django/issues{/number}","pulls_url":"https://api.github.com/repos/django/django/pulls{/number}","milestones_url":"https://api.github.com/repos/django/django/milestones{/number}","notifications_url":"https://api.github.com/repos/django/django/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/django/django/labels{/name}","releases_url":"https://api.github.com/repos/django/django/releases{/id}","deployments_url":"https://api.github.com/repos/django/django/deployments","created_at":"2012-04-28T02:47:18Z","updated_at":"2016-11-07T00:34:58Z","pushed_at":"2016-11-06T23:26:02Z","git_url":"git://github.com/django/django.git","ssh_url":"git@github.com:django/django.git","clone_url":"https://github.com/django/django.git","svn_url":"https://github.com/django/django","homepage":"https://www.djangoproject.com/","size":214766,"stargazers_count":22009,"watchers_count":22009,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":8848,"mirror_url":null,"open_issues_count":132,"forks":8848,"open_issues":132,"watchers":22009,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/django/django/pulls/6395"},"html":{"href":"https://github.com/django/django/pull/6395"},"issue":{"href":"https://api.github.com/repos/django/django/issues/6395"},"comments":{"href":"https://api.github.com/repos/django/django/issues/6395/comments"},"review_comments":{"href":"https://api.github.com/repos/django/django/pulls/6395/comments"},"review_comment":{"href":"https://api.github.com/repos/django/django/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/django/django/pulls/6395/commits"},"statuses":{"href":"https://api.github.com/repos/django/django/statuses/8cafcb8f0a8b2d2b9e0f63aac21a307a8b9d113c"}}}}
{"actor":{"display_login":"charettes"}}