Skip to content
This repository has been archived by the owner on Jul 20, 2019. It is now read-only.

Commit

Permalink
Use faster group columns if not running on postgresql
Browse files Browse the repository at this point in the history
  • Loading branch information
tomeric committed May 19, 2010
1 parent f836c91 commit c31c2e5
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 9 deletions.
7 changes: 4 additions & 3 deletions lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb
Expand Up @@ -91,7 +91,6 @@ def all_tag_counts(options = {})

joins = joins.reverse if ActiveRecord::VERSION::MAJOR < 3


## Generate scope:
scope = ActsAsTaggableOn::Tag.scoped(:select => "#{ActsAsTaggableOn::Tag.table_name}.*, COUNT(*) AS count").order(options[:order]).limit(options[:limit])

Expand All @@ -104,17 +103,19 @@ def all_tag_counts(options = {})
at_most = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most]
having = [at_least, at_most].compact.join(' AND ')

group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(ActsAsTaggableOn::Tag) : "#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}"

if ActiveRecord::VERSION::MAJOR >= 3
# Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
scoped_select = "#{table_name}.#{primary_key}"
scope = scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})")

# We have having() in RoR 3.0 so use it:
having = having.blank? ? "COUNT(*) > 0" : "COUNT(*) > 0 AND #{having}"
scope = scope.group(grouped_column_names_for(ActsAsTaggableOn::Tag)).having(having)
scope = scope.group(group_columns).having(having)
else
# Having is not available in 2.3.x:
group_by = "#{grouped_column_names_for(ActsAsTaggableOn::Tag)} HAVING COUNT(*) > 0"
group_by = "#{group_columns} HAVING COUNT(*) > 0"
group_by << " AND #{having}" unless having.blank?
scope = scope.group(group_by)
end
Expand Down
17 changes: 14 additions & 3 deletions lib/acts_as_taggable_on/acts_as_taggable_on/core.rb
Expand Up @@ -110,7 +110,9 @@ def tagged_with(tags, options = {})
" ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"

group = "#{grouped_column_names_for(self)} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"

group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
group = "#{group_columns} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
end


Expand Down Expand Up @@ -176,8 +178,17 @@ def all_tags_on(context)
tag_table_name = ActsAsTaggableOn::Tag.table_name
tagging_table_name = ActsAsTaggableOn::Tagging.table_name

opts = ["#{tagging_table_name}.context = ?", context.to_s]
base_tags.where(opts).order("max(#{tagging_table_name}.created_at)").group("#{tag_table_name}.id, #{tag_table_name}.name").all
opts = ["#{tagging_table_name}.context = ?", context.to_s]
scope = base_tags.where(opts)

if ActsAsTaggableOn::Tag.using_postgresql?
group_columns = grouped_column_names_for(ActsAsTaggableOn::Tag)
scope = scope.order("max(#{tagging_table_name}.created_at)").group(group_columns)
else
scope = scope.group("#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}")
end

scope.all
end

##
Expand Down
8 changes: 6 additions & 2 deletions lib/acts_as_taggable_on/acts_as_taggable_on/related.rb
Expand Up @@ -42,10 +42,12 @@ def matching_contexts_for(search_context, result_context, klass, options = {})

exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass

group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : "#{klass.table_name}.#{klass.primary_key}"

klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.id) AS count",
:from => "#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}",
:conditions => ["#{exclude_self} #{klass.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?) AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_to_find, result_context],
:group => grouped_column_names_for(klass),
:group => group_columns,
:order => "count DESC" }.update(options))
end

Expand All @@ -54,10 +56,12 @@ def related_tags_for(context, klass, options = {})

exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass

group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : "#{klass.table_name}.#{klass.primary_key}"

klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.id) AS count",
:from => "#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}",
:conditions => ["#{exclude_self} #{klass.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?)", tags_to_find],
:group => grouped_column_names_for(klass),
:group => group_columns,
:order => "count DESC" }.update(options))
end
end
Expand Down
6 changes: 5 additions & 1 deletion lib/acts_as_taggable_on/tag.rb
Expand Up @@ -14,6 +14,10 @@ class Tag < ::ActiveRecord::Base
validates_uniqueness_of :name

### SCOPES:

def self.using_postgresql?
connection.adapter_name == 'PostgreSQL'
end

def self.named(name)
where(["name #{like_operator} ?", name])
Expand Down Expand Up @@ -66,7 +70,7 @@ def count
class << self
private
def like_operator
connection.adapter_name == 'PostgreSQL' ? 'ILIKE' : 'LIKE'
using_postgresql? ? 'ILIKE' : 'LIKE'
end
end

Expand Down

0 comments on commit c31c2e5

Please sign in to comment.