From 01a8cb8e34b8fb1592b759d0130c4d04f65c6de4 Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Wed, 1 Feb 2012 12:48:28 -0800 Subject: [PATCH] evil queries have their own house. --- lib/diaspora/user/querying.rb | 163 +++++----------------------------- lib/evil_query.rb | 118 ++++++++++++++++++++++++ lib/stream/multi.rb | 2 +- 3 files changed, 142 insertions(+), 141 deletions(-) create mode 100644 lib/evil_query.rb diff --git a/lib/diaspora/user/querying.rb b/lib/diaspora/user/querying.rb index 4ab9566c3..ab7db1a47 100644 --- a/lib/diaspora/user/querying.rb +++ b/lib/diaspora/user/querying.rb @@ -4,148 +4,18 @@ require File.join(Rails.root, 'lib', 'diaspora', 'redis_cache') +require File.join(Rails.root, 'lib', 'evil_query') + + +#TODO: THIS FILE SHOULD NOT EXIST, EVIL SQL SHOULD BE ENCAPSULATED IN EvilQueries, +#throwing all of this stuff in user violates demeter like WHOA + module Diaspora - module EvilQuery - def self.legacy_prep_opts(klass, opts) - defaults = { - :order => 'created_at DESC', - :limit => 15, - :hidden => false - } - defaults[:type] = Stream::Base::TYPES_OF_POST_IN_STREAM if klass == Post - opts = defaults.merge(opts) - - opts[:order_field] = opts[:order].split.first.to_sym - opts[:order_with_table] = klass.table_name + '.' + opts[:order] - - opts[:max_time] = Time.at(opts[:max_time]) if opts[:max_time].is_a?(Integer) - opts[:max_time] ||= Time.now + 1 - opts - end - - class Base - def fetch_ids!(relation, id_column) - #the relation should be ordered and limited by here - @class.connection.select_values(relation.select(id_column).to_sql) - end - end - - class MultiStream < Base - def initialize(user, order, max_time, include_spotlight) - @user = user - @class = Post - @order = order - @max_time = max_time - @include_spotlight = include_spotlight - end - - def make_relation! - post_ids = aspects_post_ids! + ids!(followed_tags_posts!) + ids!(mentioned_posts) - post_ids += ids!(community_spotlight_posts!) if @include_spotlight - Post.where(:id => post_ids) - end - - def aspects_post_ids! - @user.visible_shareable_ids(Post, :limit => 15, :order => "#{@order} DESC", :max_time => @max_time, :all_aspects? => true, :by_members_of => @user.aspect_ids) - end - - def followed_tags_posts! - StatusMessage.public_tag_stream(@user.followed_tag_ids) - end - - def mentioned_posts - StatusMessage.where_person_is_mentioned(@user.person) - end - - def community_spotlight_posts! - Post.all_public.where(:author_id => fetch_ids!(Person.community_spotlight, 'id')) - end - - def ids!(query) - fetch_ids!(query.for_a_stream(@max_time, @order), 'posts.id') - end - end - - class VisibleShareableById < Base - def initialize(user, klass, key, id, conditions={}) - @querent = user - @class = klass - @key = key - @id = id - @conditions = conditions - end - - def post! - #small optimization - is this optimal order?? - querent_is_contact.first || querent_is_author.first || public_post.first - end - - protected - - def querent_is_contact - @class.where(@key => @id).joins(:contacts).where(:contacts => {:user_id => @querent.id}).where(@conditions).select(@class.table_name+".*") - end - - def querent_is_author - @class.where(@key => @id, :author_id => @querent.person.id).where(@conditions) - end - - def public_post - @class.where(@key => @id, :public => true).where(@conditions) - end - end - - class ShareablesFromPerson < Base - def initialize(querent, klass, person) - @querent = querent - @class = klass - @person = person - end - - def make_relation! - return querents_posts if @person == @querent.person - - # persons_private_visibilities and persons_public_posts have no limit which is making shareable_ids gigantic. - # perhaps they should the arrays should be merged and sorted - # then the query at the bottom of this method can be paginated or something? - - shareable_ids = contact.present? ? fetch_ids!(persons_private_visibilities, "share_visibilities.shareable_id") : [] - shareable_ids += fetch_ids!(persons_public_posts, table_name + ".id") - - @class.where(:id => shareable_ids, :pending => false). - select('DISTINCT '+table_name+'.*'). - order(table_name+".created_at DESC") - end - - protected - - def table_name - @class.table_name - end - - def contact - @contact ||= @querent.contact_for(@person) - end - - def querents_posts - @querent.person.send(table_name).where(:pending => false).order("#{table_name}.created_at DESC") - end - - def persons_private_visibilities - contact.share_visibilities.where(:hidden => false, :shareable_type => @class.to_s) - end - - def persons_public_posts - @person.send(table_name).where(:public => true).select(table_name+'.id') - end - end - end - module UserModules module Querying def find_visible_shareable_by_id(klass, id, opts={} ) key = (opts.delete(:key) || :id) - EvilQuery::VisibleShareableById.new(self, klass, key, id, opts).post! + ::EvilQuery::VisibleShareableById.new(self, klass, key, id, opts).post! end def visible_shareables(klass, opts={}) @@ -292,11 +162,11 @@ module Diaspora end def posts_from(person) - EvilQuery::ShareablesFromPerson.new(self, Post, person).make_relation! + ::EvilQuery::ShareablesFromPerson.new(self, Post, person).make_relation! end def photos_from(person) - EvilQuery::ShareablesFromPerson.new(self, Photo, person).make_relation! + ::EvilQuery::ShareablesFromPerson.new(self, Photo, person).make_relation! end protected @@ -315,7 +185,20 @@ module Diaspora # @return [Hash] def prep_opts(klass, opts) - EvilQuery.legacy_prep_opts(klass, opts) + defaults = { + :order => 'created_at DESC', + :limit => 15, + :hidden => false + } + defaults[:type] = Stream::Base::TYPES_OF_POST_IN_STREAM if klass == Post + opts = defaults.merge(opts) + + opts[:order_field] = opts[:order].split.first.to_sym + opts[:order_with_table] = klass.table_name + '.' + opts[:order] + + opts[:max_time] = Time.at(opts[:max_time]) if opts[:max_time].is_a?(Integer) + opts[:max_time] ||= Time.now + 1 + opts end end end diff --git a/lib/evil_query.rb b/lib/evil_query.rb new file mode 100644 index 000000000..766c4a599 --- /dev/null +++ b/lib/evil_query.rb @@ -0,0 +1,118 @@ +module EvilQuery + class Base + def fetch_ids!(relation, id_column) + #the relation should be ordered and limited by here + @class.connection.select_values(relation.select(id_column).to_sql) + end + end + + class MultiStream < Base + def initialize(user, order, max_time, include_spotlight) + @user = user + @class = Post + @order = order + @max_time = max_time + @include_spotlight = include_spotlight + end + + def make_relation! + post_ids = aspects_post_ids! + ids!(followed_tags_posts!) + ids!(mentioned_posts) + post_ids += ids!(community_spotlight_posts!) if @include_spotlight + Post.where(:id => post_ids) + end + + def aspects_post_ids! + @user.visible_shareable_ids(Post, :limit => 15, :order => "#{@order} DESC", :max_time => @max_time, :all_aspects? => true, :by_members_of => @user.aspect_ids) + end + + def followed_tags_posts! + StatusMessage.public_tag_stream(@user.followed_tag_ids) + end + + def mentioned_posts + StatusMessage.where_person_is_mentioned(@user.person) + end + + def community_spotlight_posts! + Post.all_public.where(:author_id => fetch_ids!(Person.community_spotlight, 'id')) + end + + def ids!(query) + fetch_ids!(query.for_a_stream(@max_time, @order), 'posts.id') + end + end + + class VisibleShareableById < Base + def initialize(user, klass, key, id, conditions={}) + @querent = user + @class = klass + @key = key + @id = id + @conditions = conditions + end + + def post! + #small optimization - is this optimal order?? + querent_is_contact.first || querent_is_author.first || public_post.first + end + + protected + + def querent_is_contact + @class.where(@key => @id).joins(:contacts).where(:contacts => {:user_id => @querent.id}).where(@conditions).select(@class.table_name+".*") + end + + def querent_is_author + @class.where(@key => @id, :author_id => @querent.person.id).where(@conditions) + end + + def public_post + @class.where(@key => @id, :public => true).where(@conditions) + end + end + + class ShareablesFromPerson < Base + def initialize(querent, klass, person) + @querent = querent + @class = klass + @person = person + end + + def make_relation! + return querents_posts if @person == @querent.person + + # persons_private_visibilities and persons_public_posts have no limit which is making shareable_ids gigantic. + # perhaps they should the arrays should be merged and sorted + # then the query at the bottom of this method can be paginated or something? + + shareable_ids = contact.present? ? fetch_ids!(persons_private_visibilities, "share_visibilities.shareable_id") : [] + shareable_ids += fetch_ids!(persons_public_posts, table_name + ".id") + + @class.where(:id => shareable_ids, :pending => false). + select('DISTINCT '+table_name+'.*'). + order(table_name+".created_at DESC") + end + + protected + + def table_name + @class.table_name + end + + def contact + @contact ||= @querent.contact_for(@person) + end + + def querents_posts + @querent.person.send(table_name).where(:pending => false).order("#{table_name}.created_at DESC") + end + + def persons_private_visibilities + contact.share_visibilities.where(:hidden => false, :shareable_type => @class.to_s) + end + + def persons_public_posts + @person.send(table_name).where(:public => true).select(table_name+'.id') + end + end +end diff --git a/lib/stream/multi.rb b/lib/stream/multi.rb index b1944e6ea..f191202c6 100644 --- a/lib/stream/multi.rb +++ b/lib/stream/multi.rb @@ -16,7 +16,7 @@ class Stream::Multi < Stream::Base end def posts - @posts ||= Diaspora::EvilQuery::MultiStream.new(user, order, max_time, include_community_spotlight?).make_relation! + @posts ||= ::EvilQuery::MultiStream.new(user, order, max_time, include_community_spotlight?).make_relation! end #emits an enum of the groups which the post appeared