Class: SmartTuple
- Inherits:
-
Object
- Object
- SmartTuple
- Defined in:
- lib/smart_tuple.rb
Overview
SQL condition builder.
tup = SmartTuple.new(" AND ")
tup << {:brand => "Nokia"}
tup << ["min_price >= ?", 75]
tup.compile # => ["brand = ? AND min_price >= ?", "Nokia", 75]
Instance Attribute Summary collapse
-
#args ⇒ Object
readonly
Array of SQL argument parts.
-
#brackets ⇒ Object
Put brackets around statements.
-
#glue ⇒ Object
String to glue statements together.
-
#statements ⇒ Object
readonly
Array of SQL statement parts.
Instance Method Summary collapse
-
#+(arg) ⇒ Object
Add a statement, return new object.
-
#<<(arg) ⇒ Object
Add a statement, return self.
-
#add_each(collection, &block) ⇒ Object
Iterate over collection and add block’s result to self once per each record.
-
#clear ⇒ Object
Clear self.
-
#compile ⇒ Object
(also: #to_a)
Compile self into an array.
-
#empty? ⇒ Boolean
Return
true
if self is empty. -
#initialize(glue, attrs = {}) ⇒ SmartTuple
constructor
Initializer.
-
#initialize_copy(src) ⇒ Object
Service initializer for
dup
. -
#size ⇒ Object
Get number of sub-statements.
Constructor Details
#initialize(glue, attrs = {}) ⇒ SmartTuple
Initializer.
new(" AND ")
new(" OR ", :brackets => true)
26 27 28 29 30 |
# File 'lib/smart_tuple.rb', line 26 def initialize(glue, attrs = {}) @glue = glue clear attrs.each {|k, v| send("#{k}=", v)} end |
Instance Attribute Details
#args ⇒ Object (readonly)
Array of SQL argument parts.
9 10 11 |
# File 'lib/smart_tuple.rb', line 9 def args @args end |
#brackets ⇒ Object
Put brackets around statements. true
, false
or :auto
. Default:
:auto
14 15 16 |
# File 'lib/smart_tuple.rb', line 14 def brackets @brackets end |
#glue ⇒ Object
String to glue statements together.
17 18 19 |
# File 'lib/smart_tuple.rb', line 17 def glue @glue end |
#statements ⇒ Object (readonly)
Array of SQL statement parts.
20 21 22 |
# File 'lib/smart_tuple.rb', line 20 def statements @statements end |
Instance Method Details
#+(arg) ⇒ Object
Add a statement, return new object. See #<<.
SmartTuple.new(" AND ") + {:brand => "Nokia"} + ["max_price <= ?", 300]
41 42 43 44 |
# File 'lib/smart_tuple.rb', line 41 def +(arg) # Since #<< supports chaining, it boils down to this. dup << arg end |
#<<(arg) ⇒ Object
Add a statement, return self.
# Array.
tup << ["brand = ?", "Nokia"]
tup << ["brand = ? AND color = ?", "Nokia", "Black"]
# Hash.
tup << {:brand => "Nokia"}
tup << {:brand => "Nokia", :color => "Black"}
# Another SmartTuple.
tup << other_tuple
# String. Generally NOT recommended.
tup << "min_price >= 75"
Adding anything empty or blank (where appropriate) has no effect on the receiver:
tup << nil
tup << []
tup << {}
tup << another_empty_tuple
tup << ""
tup << " " # Will be treated as blank if ActiveSupport is on.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/smart_tuple.rb', line 70 def <<(arg) # NOTE: Autobracketing is placing `[value]` instead of `value` into `@statements`. #compile understands it. # Chop off everything empty first time. if arg.nil? or (arg.empty? rescue false) or (arg.blank? rescue false) elsif arg.is_a? String or (arg.acts_like? :string rescue false) @statements << arg.to_s elsif arg.is_a? Array # NOTE: If arg == [], the execution won't get here. # So, we've got at least one element. Therefore stmt will be scalar, and args -- DEFINITELY an array. stmt, args = arg[0], arg[1..-1] if not (stmt.nil? or (stmt.empty? rescue false) or (stmt.blank? rescue false)) # Help do autobracketing later. Here we can ONLY judge by number of passed arguments. @statements << (args.size > 1 ? [stmt] : stmt) @args += args end elsif arg.is_a? Hash arg.each do |k, v| if v.nil? # NOTE: AR supports it for Hashes only. ["kk = ?", nil] will not be converted. @statements << "#{k} IS NULL" else @statements << "#{k} = ?" @args << v end end elsif arg.is_a? self.class # NOTE: If arg is empty, the execution won't get here. # Autobrackets here are smarter, than in Array processing case. stmt = arg.compile[0] @statements << ((arg.size > 1 or arg.args.size > 1) ? [stmt] : stmt) @args += arg.args else raise ArgumentError, "Invalid statement #{arg.inspect}" end # Return self, it's IMPORTANT to make chaining possible. self end |
#add_each(collection, &block) ⇒ Object
Iterate over collection and add block’s result to self once per each record.
add_each(brands) do |v|
["brand = ?", v]
end
Can be conditional:
tup.add_each(["Nokia", "Motorola"]) do |v|
["brand = ?", v] if v =~ /^Moto/
end
122 123 124 125 126 127 128 129 130 131 |
# File 'lib/smart_tuple.rb', line 122 def add_each(collection, &block) raise ArgumentError, "Code block expected" if not block collection.each do |v| self << yield(v) end # This is IMPORTANT. self end |
#clear ⇒ Object
Clear self.
144 145 146 147 148 149 150 151 |
# File 'lib/smart_tuple.rb', line 144 def clear @statements = [] @args = [] @brackets = :auto # `Array` does it like this. We do either. self end |
#compile ⇒ Object Also known as: to_a
Compile self into an array. Empty self yields empty array.
compile # => []
compile # => ["brand = ? AND min_price >= ?", "Nokia", 75]
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/smart_tuple.rb', line 157 def compile return [] if empty? # Build "bracketed" statements. bsta = @statements.map do |s| auto_brackets, scalar_s = s.is_a?(Array) ? [true, s[0]] : [false, s] # Logic: # brackets | auto | result # ----------|-------|------- # true | * | true # false | * | false # :auto | true | true # :auto | false | false brackets = if @statements.size < 2 # If there are no neighboring statements, there WILL BE NO brackets in any case. false elsif @brackets == true or @brackets == false @brackets elsif @brackets == :auto auto_brackets else raise "Unknown @brackets value #{@brackets.inspect}, SE" end if brackets ["(", scalar_s, ")"].join else scalar_s end end [bsta.join(glue)] + @args end |
#empty? ⇒ Boolean
Return true
if self is empty.
tup = SmartTuple.new(" AND ")
tup.empty? # => true
198 199 200 |
# File 'lib/smart_tuple.rb', line 198 def empty? @statements.empty? end |
#initialize_copy(src) ⇒ Object
Service initializer for dup
.
33 34 35 36 |
# File 'lib/smart_tuple.rb', line 33 def initialize_copy(src) #:nodoc: @statements = src.statements.dup @args = src.args.dup end |
#size ⇒ Object
Get number of sub-statements.
203 204 205 |
# File 'lib/smart_tuple.rb', line 203 def size @statements.size end |