Skip to content

Commit 4b19eef

Browse files
committed
ternary_value_flag feature without tests
1 parent c28a287 commit 4b19eef

2 files changed

Lines changed: 296 additions & 57 deletions

File tree

TERNARY_UPDATE_README.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# FlagShihTzu_Ternary_flag_update
2+
3+
## Summary
4+
5+
The updated functionality of the gem allow flag(s) to be set as nil, i.e neither true nor false.
6+
7+
8+
### Defaults (Important)
9+
10+
* As, the rails default limit(size) of an integer is 4, the ternary update restricts the support of total no. of flags to 15. Change the limit value in the migration to increase total no. of flags.
11+
* Due to the default of `0`, *all flags* are initially set to "false". To set all flags to nil initially, assign default value to 2^(32-1)-1 i.e 2147483647 in the migration.
12+
13+
14+
### Bit Fields: How it stores the three values
15+
16+
As said, FlagShihTzu uses a single integer column to store the values for all
17+
the defined flags as a [bit field][bitfield].
18+
19+
So, to accomodate 3 values(true, false and nil), a combination of 2 bits is used to store one of the three value via following mapping:
20+
21+
`---+---+---+---+
22+
| Value | Bits |
23+
| | |
24+
`---+---+---+---+
25+
| false | 00 |
26+
`---+---+---+---+
27+
| true | 10 |
28+
`---+---+---+---+
29+
| nil | 11 |
30+
`---+---+---+---+
31+
32+
The bit position of a flag corresponds to the given key.
33+
34+
This way, we can use [bitwise operators][bit_operation] on the stored integer value to set, unset
35+
and check individual flags.
36+
37+
`---+---+---+---+---+---+ +---+---+---+---+---+---`
38+
| | | | | | | |
39+
Flag position | 3 | 2 | 1 | | 3 | 2 | 1 |
40+
(flag key) | | | | | | | |
41+
`---+---+---+---+---+---+ +---+---+---+---+---+---`
42+
| e | s | w | | e | s | w |
43+
| l | h | a | | l | h | a |
44+
| e | i | r | | e | i | r |
45+
| c | e | p | | c | e | p |
46+
| t | l | d | | t | l | d |
47+
| r | d | r | | r | d | r |
48+
| o | s | i | | o | s | i |
49+
| l | | v | | l | | v |
50+
| y | | e | | y | | e |
51+
| t | | | | t | | |
52+
| e | | | | e | | |
53+
| s | | | | s | | |
54+
`---+---+---+---+---+---+ +---+---+---+---+---+---`
55+
| true | false | nil | | nil | true | false |
56+
Flag Value `---+---|---+---|---+---+ +---+---|---+---|---+---`
57+
| 0 1 | 0 0 | 1 1 | | 1 1 | 0 1 | 0 0 |
58+
`---+---+---+---|---+---+ +---+---|---+---|---+---`
59+
Bit Value | 32 16 | 8 4 | 2 1 | = 16 + 2 + 1 = 19 | 32 16 | 8 4 | 2 1 | = 32 + 16 + 4 = 52
60+
`---+---+---+---|---+---+ +---+---|---+---|---+---`
61+
62+
Read more about [bit fields][bit_field] here: http://en.wikipedia.org/wiki/Bit_field
63+
64+
65+
### Bang Method for nil value
66+
67+
When setting the `:bang_methods` option to true, the following method also gets defined:
68+
69+
Spaceship#electrolytes_nil! # will save the bitwise equivalent of electrolytes = nil on the record
70+
71+
which clears the current value of the electrolytes flag.
72+
73+
74+
### Generated named scope for nil flags
75+
76+
The following new named scope(s) become available:
77+
78+
```ruby
79+
Spaceship.warpdrive_nil # :conditions => "(spaceships.flags in (3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,71,75,79,83,87,91,95))"
80+
```
81+
82+
83+
### Support for manually building conditions
84+
85+
The following class method gets added for nil condition for supporting manually building
86+
ActiveRecord conditions:
87+
88+
```ruby
89+
Spaceship.warpdrive_nil_condition # :conditions => "(spaceships.flags in (3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,71,75,79,83,87,91,95))"
90+
```
91+
92+
93+
### Query mode
94+
95+
While the default way of building the SQL conditions uses an `IN()` list
96+
(as shown above) and the same is also used in flag_shih_tzu, this approach will not work well in this gem for higher number of flags,
97+
as the value list for `IN()` grows a lot faster.
98+
99+
So, in this gem, flag query mode is changed to `:bit_operator`
100+
from `:in_list`
101+
102+
This will modify the generated condition and named_scope methods to use bit
103+
operators in the SQL instead of an `IN()` list:
104+
105+
```ruby
106+
Spaceship.warpdrive_condition # "(spaceships.flags & 3 = 1)",
107+
Spaceship.not_warpdrive_condition # "(spaceships.flags & 3 = 0)",
108+
Spaceship.warpdrive_nil_condition # "(spaceships.flags & 3 = 3)",
109+
Spaceship.shields_condition # "(spaceships.flags & 12 = 4)",
110+
Spaceship.not_shields_condition # "(spaceships.flags & 12 = 0)",
111+
Spaceship.shields_nil_condition # "(spaceships.flags & 12 = 12)",
112+
113+
Spaceship.warpdrive # :conditions => "(spaceships.flags & 3 = 1)"
114+
Spaceship.not_warpdrive # :conditions => "(spaceships.flags & 3 = 0)"
115+
Spaceship.warpdrive_nil # :conditions => "(spaceships.flags & 3 = 3)"
116+
Spaceship.shields # :conditions => "(spaceships.flags & 12 = 4)"
117+
Spaceship.not_shields # :conditions => "(spaceships.flags & 12 = 0)"
118+
Spaceship.shields_nil # :conditions => "(spaceships.flags & 12 = 12)"
119+
```

0 commit comments

Comments
 (0)