From 1ec5522d494ae11349780b32e31430e39103b92e Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 4 Oct 2013 20:17:27 -0400 Subject: [PATCH] Eager-load participant when querying elsewhere --- branch.sql | 44 ++++++++++++++++++++++++++++++ gittip/elsewhere/__init__.py | 29 ++++++++++++++------ gittip/models/account_elsewhere.py | 2 +- tests/test_elsewhere_twitter.py | 15 +++++----- 4 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 branch.sql diff --git a/branch.sql b/branch.sql new file mode 100644 index 0000000000..d4969e7453 --- /dev/null +++ b/branch.sql @@ -0,0 +1,44 @@ +------------------------------------------------------------------------------- +-- https://github.com/gittip/www.gittip.com/pull/1369 + + +-- The following lets us cast queries to elsewhere_with_participant to get the +-- participant data dereferenced and returned in a composite type along with +-- the elsewhere data. Then we can register orm.Models in the application for +-- both participant and elsewhere_with_participant, and when we cast queries +-- elsewhere.*::elsewhere_with_participant, we'll get a hydrated Participant +-- object at .participant. Woo-hoo! + + +BEGIN; + + CREATE TYPE elsewhere_with_participant AS + ( id integer + , platform text + , user_id text + , user_info hstore + , is_locked boolean + , participant participants + ); + + CREATE OR REPLACE FUNCTION load_participant_for_elsewhere (elsewhere) + RETURNS elsewhere_with_participant + AS $$ + + SELECT $1.id + , $1.platform + , $1.user_id + , $1.user_info + , $1.is_locked + , participants.*::participants + FROM participants + WHERE participants.username = $1.participant + ; + + $$ LANGUAGE SQL; + + + CREATE CAST (elsewhere AS elsewhere_with_participant) + WITH FUNCTION load_participant_for_elsewhere(elsewhere); + +END; diff --git a/gittip/elsewhere/__init__.py b/gittip/elsewhere/__init__.py index f46a6f1b23..a05e542d1b 100644 --- a/gittip/elsewhere/__init__.py +++ b/gittip/elsewhere/__init__.py @@ -50,7 +50,7 @@ def __init__(self, db): def load(self, username): - """Given a unicode, return an AccountElsewhere object. + """Given a username on the other platform, return an AccountElsewhere object. """ typecheck(username, UnicodeWithParams) try: @@ -61,16 +61,29 @@ def load(self, username): def load_from_db(self, username): - return self.db.one( "SELECT elsewhere.*::elsewhere " - "FROM elsewhere " - "WHERE platform=%s " - "AND user_info->%s = %s" - , (self.name, self.username_key, username) - , default=UnknownAccountElsewhere - ) + """Given a username on the other platform, return an AccountElsewhere object. + + If the account elsewhere is unknown to us, we raise UnknownAccountElsewhere. + + """ + return self.db.one(""" + + SELECT elsewhere.*::elsewhere_with_participant + FROM elsewhere + WHERE platform=%s + AND user_info->%s = %s + + """, (self.name, self.username_key, username), default=UnknownAccountElsewhere) def load_from_api(self, username): + """Given a username on the other platform, return an AccountElsewhere object. + + The first thing we do is hit the API of the other platform, then we use + that to upsert our own elsewhere table, before handing back off to + load_from_db. + + """ # Hit the platform's API to get user info. # ======================================== diff --git a/gittip/models/account_elsewhere.py b/gittip/models/account_elsewhere.py index b5b57d1666..80ddac0bf2 100644 --- a/gittip/models/account_elsewhere.py +++ b/gittip/models/account_elsewhere.py @@ -5,7 +5,7 @@ class AccountElsewhere(Model): - typname = "elsewhere" + typname = "elsewhere_with_participant" def get_html_url(self): diff --git a/tests/test_elsewhere_twitter.py b/tests/test_elsewhere_twitter.py index 335d55dd0e..e2ee6eee68 100644 --- a/tests/test_elsewhere_twitter.py +++ b/tests/test_elsewhere_twitter.py @@ -26,16 +26,17 @@ def test_twitter_resolve_resolves(self): assert actual == expected - def test_get_user_info_gets_user_info(self): - twitter.TwitterAccount("1", {'screen_name': 'alice'}).opt_in('alice') - expected = {"screen_name": "alice"} - actual = twitter.get_user_info('alice') - assert actual == expected - - @mock.patch('gittip.elsewhere.twitter.Twitter.hit_api') def test_can_load_account_elsewhere_from_twitter(self, hit_api): hit_api.return_value = {"id": "123", "screen_name": "alice"} alice_on_twitter = self.elsewhere.twitter.load(UnicodeWithParams('alice', {})) assert alice_on_twitter.user_id == "123" + + + @mock.patch('gittip.elsewhere.twitter.Twitter.hit_api') + def test_account_elsewhere_has_participant_object_on_it(self, hit_api): + hit_api.return_value = {"id": "123", "screen_name": "alice"} + alice_on_twitter = self.elsewhere.twitter.load(UnicodeWithParams('alice', {})) + import pdb; pdb.set_trace() + assert alice_on_twitter.participant.username == 'alice'