Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Implemented chained_flags_with, which allows optimizing the bit search #23

Merged
merged 1 commit into from

3 participants

@pboling
Owner

When you chain multiple named scope generated by FlagShihTzu,
generated ActiveRecord query would look like this.

Spaceship.warpdrive.shields.not_electrolytes
# => (spaceships.flags in (1,3,5,7)) AND (spaceships.flags in (2,3,6,7)) AND (spaceships.flags not in (4,5,6,7))

With the chained_flags_with introduced with this patch, you can write
the same query in an optimized search.

Spaceship.chained_flags_with("flags", :warpdrive, :shields, :not_electrolytes)
# => (spaceships.flags in (3))

You can also name it with the named scope:

scope :listed, chained_flags_with("flags", :warpdrive, :shields, :not_electrolytes)

@miyagawa miyagawa Implemented chained_flags_with, which allows optimizing the bit search
When you chain multiple named scope generated by FlagShihTzu,
generated ActiveRecord query would look like this.

  Spaceship.warpdrive.shields.not_electrolytes
  # => (spaceships.flags in (1,3,5,7)) AND (spaceships.flags in (2,3,6,7)) AND (spaceships.flags not in (4,5,6,7))

With the chained_flags_with introduced with this patch, you can write
the same query in an optimized search.

  Spaceship.chained_flags_with("flags", :warpdrive, :shields, :not_electrolytes)
  # => (spaceships.flags in (3))

You can also name it with the named scope:

  scope :listed, chained_flags_with("flags", :warpdrive, :shields, :not_electrolytes)
b56b9ac
@pboling
Owner

Please create a pull request for this! Looks awesome!

@pboling pboling was assigned
@gamov

Indeed, excellent!!

@pboling pboling merged commit b56b9ac into pboling:master
@pboling
Owner

Released in 0.3.4 (0.3.3 got skipped due to a credentials issue with RubyGems.org)

@gamov

That's awesome indeed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 25, 2012
  1. @miyagawa

    Implemented chained_flags_with, which allows optimizing the bit search

    miyagawa authored
    When you chain multiple named scope generated by FlagShihTzu,
    generated ActiveRecord query would look like this.
    
      Spaceship.warpdrive.shields.not_electrolytes
      # => (spaceships.flags in (1,3,5,7)) AND (spaceships.flags in (2,3,6,7)) AND (spaceships.flags not in (4,5,6,7))
    
    With the chained_flags_with introduced with this patch, you can write
    the same query in an optimized search.
    
      Spaceship.chained_flags_with("flags", :warpdrive, :shields, :not_electrolytes)
      # => (spaceships.flags in (3))
    
    You can also name it with the named scope:
    
      scope :listed, chained_flags_with("flags", :warpdrive, :shields, :not_electrolytes)
This page is out of date. Refresh to see the latest.
Showing with 54 additions and 0 deletions.
  1. +27 −0 lib/flag_shih_tzu.rb
  2. +27 −0 test/flag_shih_tzu_test.rb
View
27 lib/flag_shih_tzu.rb
@@ -93,8 +93,35 @@ def check_flag(flag, colmn)
raise ArgumentError, "Invalid flag '#{flag}'" if flag_mapping[colmn].nil? || !flag_mapping[colmn].include?(flag)
end
+ def chained_flags_with(*args)
+ where(chained_flags_condition(*args))
+ end
+
+ def chained_flags_condition(colmn, *args)
+ "(#{self.table_name}.#{colmn} in (#{chained_flags_values(colmn, *args).join(',')}))"
+ end
+
private
+ def chained_flags_values(colmn, *args)
+ val = (1..(2 ** flag_mapping[flag_options[colmn][:column]].length)).to_a
+ args.each do |flag|
+ neg = false
+ if flag.match /^not_/
+ neg = true
+ flag = flag.to_s.sub(/^not_/, '').to_sym
+ end
+ check_flag(flag, colmn)
+ flag_values = sql_in_for_flag(flag, colmn)
+ if neg
+ val = val - flag_values
+ else
+ val = val & flag_values
+ end
+ end
+ val
+ end
+
def parse_options(*args)
options = args.shift
if args.size >= 1
View
27 test/flag_shih_tzu_test.rb
@@ -241,6 +241,33 @@ def test_should_return_the_correct_number_of_items_from_a_named_scope
assert_equal 0, Spaceship.not_warpdrive.not_shields.count
end
+ def test_should_return_the_correct_condition_with_chained_flags
+ assert_equal "(spaceships.flags in (3,7))", Spaceship.chained_flags_condition("flags", :warpdrive, :shields)
+ assert_equal "(spaceships.flags in (7))", Spaceship.chained_flags_condition("flags", :warpdrive, :shields, :electrolytes)
+ assert_equal "(spaceships.flags in (2,6))", Spaceship.chained_flags_condition("flags", :not_warpdrive, :shields)
+ end
+
+ def test_should_return_the_correct_number_of_items_with_chained_flags_with
+ spaceship = Spaceship.new
+ spaceship.enable_flag(:warpdrive)
+ spaceship.enable_flag(:shields)
+ spaceship.save!
+ spaceship.reload
+ spaceship_2 = Spaceship.new
+ spaceship_2.enable_flag(:warpdrive)
+ spaceship_2.save!
+ spaceship_2.reload
+ spaceship_3 = Spaceship.new
+ spaceship_3.enable_flag(:shields)
+ spaceship_3.save!
+ spaceship_3.reload
+ assert_equal 2, Spaceship.chained_flags_with("flags", :warpdrive).count
+ assert_equal 1, Spaceship.chained_flags_with("flags", :warpdrive, :shields).count
+ assert_equal 1, Spaceship.chained_flags_with("flags", :warpdrive, :not_shields).count
+ assert_equal 0, Spaceship.chained_flags_with("flags", :not_warpdrive, :shields, :electrolytes).count
+ assert_equal 1, Spaceship.chained_flags_with("flags", :not_warpdrive, :shields, :not_electrolytes).count
+ end
+
def test_should_not_define_named_scopes_if_not_wanted
assert !SpaceshipWithoutNamedScopes.respond_to?(:warpdrive)
assert !SpaceshipWithoutNamedScopesOldStyle.respond_to?(:warpdrive)
Something went wrong with that request. Please try again.