bitfields 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +11 -3
- data/VERSION +1 -1
- data/benchmark/{1.rb → bit_operator_vs_in.rb} +11 -20
- data/bitfields.gemspec +2 -2
- data/lib/bitfields.rb +1 -1
- data/spec/bitfields_spec.rb +6 -6
- metadata +5 -5
data/README.markdown
CHANGED
@@ -13,8 +13,8 @@ e.g. true-false-false = 1, false-true-false = 2, true-false-true = 5 (1,2,4,8,.
|
|
13
13
|
|
14
14
|
- records changes `user.chamges == {:seller => [false, true]}`
|
15
15
|
- adds scopes `User.seller.stupid.first` (deactivate with `bitfield ..., :scopes => false`)
|
16
|
-
- builds sql `User.bitfield_sql(:insane => true, :stupid => false) == 'users.my_bits
|
17
|
-
- builds
|
16
|
+
- builds sql `User.bitfield_sql(:insane => true, :stupid => false) == '(users.my_bits & 3) = 1'`
|
17
|
+
- builds index-using sql with `bitfield ... ,:query_mode => :in_list` and `User.bitfield_sql(:insane => true, :stupid => false) == 'users.my_bits IN (2, 3)'` (2 and 1+2), often slower than :bit_operator sql especially for high number of bits
|
18
18
|
- builds update sql `User.set_bitfield_sql(:insane => true, :stupid => false) == 'my_bits = (my_bits | 6) - 4'`
|
19
19
|
- **faster sql than any other bitfield lib** through combination of multiple bits into a single sql statement
|
20
20
|
- gives access to bits `User.bitfields[:my_bits][:stupid] == 4`
|
@@ -22,7 +22,7 @@ e.g. true-false-false = 1, false-true-false = 2, true-false-true = 5 (1,2,4,8,.
|
|
22
22
|
Install
|
23
23
|
=======
|
24
24
|
As Gem: ` sudo gem install bitfields `
|
25
|
-
Or as Rails plugin: `
|
25
|
+
Or as Rails plugin: ` rails plugin install git://github.com/grosser/bitfields.git `
|
26
26
|
|
27
27
|
### Migration
|
28
28
|
ALWAYS set a default, bitfield queries will not work for NULL
|
@@ -38,6 +38,14 @@ Update all users
|
|
38
38
|
Delete the shop when a user is no longer a seller
|
39
39
|
before_save :delete_shop, :if => lambda{|u| u.changes['seller'] == [true, false]}
|
40
40
|
|
41
|
+
TIPS
|
42
|
+
====
|
43
|
+
- Never do: "#{bitfield_sql(...)} AND #{bitfield_sql(...)}", merge both into one hash
|
44
|
+
- bit_operator is faster in most cases, use :query_mode => :in_list sparingly
|
45
|
+
- standard mysql integer is 4 byte -> 32 bitfields
|
46
|
+
|
47
|
+

|
48
|
+
|
41
49
|
TODO
|
42
50
|
====
|
43
51
|
- convenient named scope `User.with_bitfields(:xxx=>true, :yy=>false)`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -1,5 +1,5 @@
|
|
1
|
-
bit_counts = [2,3,4,
|
2
|
-
record_counts = (1..
|
1
|
+
bit_counts = [2,3,4,6,8,10,12,14]
|
2
|
+
record_counts = (1..10).to_a.map{|i| i * 100_000 }
|
3
3
|
use_index = true
|
4
4
|
database = ARGV[0]
|
5
5
|
|
@@ -90,15 +90,6 @@ def test_speed(bit_counts, query_mode)
|
|
90
90
|
Hash[result]
|
91
91
|
end
|
92
92
|
|
93
|
-
#determines a unique color based on a name
|
94
|
-
def color_for(name)
|
95
|
-
name = name.inspect + "some randomness for fun"
|
96
|
-
hash = (name.hash % 1_000_000_000).to_s #get a hash of a constant size
|
97
|
-
colors = [hash[0..1], hash[2..3], hash[4..5]].map{|c| c.to_f / 100.0 * 16} #use 3 parts of the hash to get numbers from 0 to 15.99
|
98
|
-
palette = ('0'..'9').to_a + ('a'..'f').to_a #hex values 0..f
|
99
|
-
colors.map{|c| palette[c.floor].to_s * 2} * '' #each color is duplicated and the joined
|
100
|
-
end
|
101
|
-
|
102
93
|
connect(database)
|
103
94
|
create_model_table(bit_counts, use_index)
|
104
95
|
class User < ActiveRecord::Base
|
@@ -108,10 +99,10 @@ create_model_fields(bit_counts)
|
|
108
99
|
puts "creating test data"
|
109
100
|
last = 0
|
110
101
|
|
102
|
+
# collect graph data
|
111
103
|
graphs = {:bit => {}, :in => {}}
|
112
|
-
|
104
|
+
record_counts.each do |record_count|
|
113
105
|
create(bit_counts, record_count-last)
|
114
|
-
puts User.count
|
115
106
|
last = record_count
|
116
107
|
|
117
108
|
puts "testing with #{record_count} records -- bit_operator"
|
@@ -119,26 +110,26 @@ data = record_counts.map do |record_count|
|
|
119
110
|
|
120
111
|
puts "testing with #{record_count} records -- in_list"
|
121
112
|
graphs[:in][record_count] = test_speed(bit_counts, :in_list)
|
122
|
-
|
123
113
|
end
|
124
114
|
|
125
|
-
|
115
|
+
# print them
|
116
|
+
colors = {:bit => 'xx0000', :in => '0000xx'}
|
126
117
|
alpha_num = (('0'..'9').to_a + ('a'..'f').to_a).reverse
|
127
|
-
title = "bit-operator vs IN
|
118
|
+
title = "bit-operator vs IN -- #{use_index ? 'with' : 'without'} index"
|
128
119
|
url = GoogleChart::LineChart.new('600x500', title, false) do |line|
|
129
|
-
|
120
|
+
max_y = 0
|
130
121
|
graphs.each do |type, line_data|
|
131
122
|
bit_counts.each do |bit_count|
|
132
123
|
data = record_counts.map{|rc| line_data[rc][bit_count] }
|
133
124
|
name = "#{bit_count}bits (#{type})"
|
134
|
-
color = colors[type].sub('xx', alpha_num[bit_count]*2)
|
125
|
+
color = colors[type].sub('xx', alpha_num[bit_counts.index(bit_count)]*2)
|
135
126
|
line.data(name, data, color)
|
136
|
-
|
127
|
+
max_y = [data.max, max_y].max
|
137
128
|
end
|
138
129
|
end
|
139
130
|
|
140
131
|
line.axis :x, :labels => record_counts.map{|c|"#{c/1000}K"}
|
141
|
-
line.axis :y, :labels => ['0', "%.
|
132
|
+
line.axis :y, :labels => ['0', "%.3fms" % [max_y*1000]]
|
142
133
|
end.to_url
|
143
134
|
|
144
135
|
puts url
|
data/bitfields.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{bitfields}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Michael Grosser"]
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
"README.markdown",
|
19
19
|
"Rakefile",
|
20
20
|
"VERSION",
|
21
|
-
"benchmark/
|
21
|
+
"benchmark/bit_operator_vs_in.rb",
|
22
22
|
"bitfields.gemspec",
|
23
23
|
"lib/bitfields.rb",
|
24
24
|
"spec/bitfields_spec.rb",
|
data/lib/bitfields.rb
CHANGED
@@ -71,7 +71,7 @@ module Bitfields
|
|
71
71
|
private
|
72
72
|
|
73
73
|
def bitfield_sql_by_column(column, bit_values, options={})
|
74
|
-
mode = options[:query_mode] || (bitfield_options[column][:query_mode] || :
|
74
|
+
mode = options[:query_mode] || (bitfield_options[column][:query_mode] || :bit_operator)
|
75
75
|
case mode
|
76
76
|
when :in_list then
|
77
77
|
max = (bitfields[column].values.max * 2) - 1
|
data/spec/bitfields_spec.rb
CHANGED
@@ -150,23 +150,23 @@ describe Bitfields do
|
|
150
150
|
|
151
151
|
describe :bitfield_sql do
|
152
152
|
it "includes true states" do
|
153
|
-
User.bitfield_sql(:insane => true).should == 'users.bits IN (2,3,6,7)' # 2, 1+2, 2+4, 1+2+4
|
153
|
+
User.bitfield_sql({:insane => true}, :query_mode => :in_list).should == 'users.bits IN (2,3,6,7)' # 2, 1+2, 2+4, 1+2+4
|
154
154
|
end
|
155
155
|
|
156
156
|
it "includes invalid states" do
|
157
|
-
User.bitfield_sql(:insane => false).should == 'users.bits IN (0,1,4,5)' # 0, 1, 4, 4+1
|
157
|
+
User.bitfield_sql({:insane => false}, :query_mode => :in_list).should == 'users.bits IN (0,1,4,5)' # 0, 1, 4, 4+1
|
158
158
|
end
|
159
159
|
|
160
160
|
it "can combine multiple fields" do
|
161
|
-
User.bitfield_sql(:seller => true, :insane => true).should == 'users.bits IN (3,7)' # 1+2, 1+2+4
|
161
|
+
User.bitfield_sql({:seller => true, :insane => true}, :query_mode => :in_list).should == 'users.bits IN (3,7)' # 1+2, 1+2+4
|
162
162
|
end
|
163
163
|
|
164
164
|
it "can combine multiple fields with different values" do
|
165
|
-
User.bitfield_sql(:seller => true, :insane => false).should == 'users.bits IN (1,5)' # 1, 1+4
|
165
|
+
User.bitfield_sql({:seller => true, :insane => false}, :query_mode => :in_list).should == 'users.bits IN (1,5)' # 1, 1+4
|
166
166
|
end
|
167
167
|
|
168
168
|
it "combines multiple columns into one sql" do
|
169
|
-
sql = MultiBitUser.bitfield_sql(:seller => true, :insane => false, :one => true, :four => true)
|
169
|
+
sql = MultiBitUser.bitfield_sql({:seller => true, :insane => false, :one => true, :four => true}, :query_mode => :in_list)
|
170
170
|
sql.should == 'users.bits IN (1,5) AND users.more_bits IN (5,7)' # 1, 1+4 AND 1+4, 1+2+4
|
171
171
|
end
|
172
172
|
|
@@ -174,7 +174,7 @@ describe Bitfields do
|
|
174
174
|
u1 = MultiBitUser.create!(:seller => true, :one => true)
|
175
175
|
u2 = MultiBitUser.create!(:seller => true, :one => false)
|
176
176
|
u3 = MultiBitUser.create!(:seller => false, :one => false)
|
177
|
-
MultiBitUser.all(:conditions => MultiBitUser.bitfield_sql(:seller => true, :one => false)).should == [u2]
|
177
|
+
MultiBitUser.all(:conditions => MultiBitUser.bitfield_sql({:seller => true, :one => false}, :query_mode => :in_list)).should == [u2]
|
178
178
|
end
|
179
179
|
|
180
180
|
describe 'with bit operator mode' do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitfields
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Michael Grosser
|
@@ -31,7 +31,7 @@ files:
|
|
31
31
|
- README.markdown
|
32
32
|
- Rakefile
|
33
33
|
- VERSION
|
34
|
-
- benchmark/
|
34
|
+
- benchmark/bit_operator_vs_in.rb
|
35
35
|
- bitfields.gemspec
|
36
36
|
- lib/bitfields.rb
|
37
37
|
- spec/bitfields_spec.rb
|