Class: Caboose::EZ::Condition
- Inherits:
-
Object
- Object
- Caboose::EZ::Condition
- Defined in:
- lib/og/ez/condition.rb
Overview
EZ::Condition plugin for generating the :conditions where clause for ActiveRecord::Base.find. And an extension to ActiveRecord::Base called AR::Base.find_with_conditions that takes a block and builds the where clause dynamically for you.
Instance Attribute Summary collapse
-
#clauses ⇒ Object
readonly
these are also reserved words regarding SQL column names use esc_* prefix to circumvent any issues.
-
#inner ⇒ Object
Returns the value of attribute inner.
-
#outer ⇒ Object
Returns the value of attribute outer.
Instance Method Summary collapse
-
#<<(condition, outer = nil) ⇒ Object
(also: #sql_condition, #add_sql, #clone_from, #append)
Append a condition element, which can be one of the following: - String: raw sql string - ActiveRecord instance, for attribute or PK cloning - Condition or Clause with to_sql method and outer property - Array in ActiveRecord format [‘column = ?’, 2].
-
#and_condition(*args, &block) ⇒ Object
(also: #all)
Shortcut for adding a :and boolean joined subcondition.
-
#clause(name, *args) ⇒ Object
You can define clauses dynamicly using this method.
-
#define_sub(*args, &block) ⇒ Object
(also: #sub, #condition)
Create subcondition from a block, optionally specifying table_name, outer and inner.
-
#initialize(*args, &block) ⇒ Condition
constructor
Initialize @clauses and eval the block so it invokes method_missing.
-
#method_missing(name, *args, &block) ⇒ Object
When invoked with the name of the column in each statement inside the block: A new Clause instance is created and recieves the args.
-
#or_condition(*args, &block) ⇒ Object
(also: #any)
Shortcut for adding a :or boolean joined subcondition.
-
#to_sql(logic = @inner) ⇒ Object
Loop over all Clause onjects in @clauses array and call to_sql on each instance.
Constructor Details
#initialize(*args, &block) ⇒ Condition
Initialize @clauses and eval the block so it invokes method_missing.
25 26 27 28 29 30 31 32 33 |
# File 'lib/og/ez/condition.rb', line 25 def initialize(*args, &block) = args.last.is_a?(Hash) ? args.last : {} [:table_name] = args.first if args.first.kind_of? Symbol @table_name = .delete(:table_name) || nil @outer = .delete(:outer) || :and @inner = .delete(:inner) || :and @clauses = [] instance_eval(&block) if block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
When invoked with the name of the column in each statement inside the block: A new Clause instance is created and recieves the args. Then the operator hits method_missing and gets sent to a new Clause instance where it either matches one of the defined ops or hits method_missing there.
When invoked with an attached block a subcondition is created. The name is regarded as the table_name, additional parameters for outer and inner are passed on.
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/og/ez/condition.rb', line 43 def method_missing(name, *args, &block) if block_given? # handle name as table_name and create a subcondition = args.last.is_a?(Hash) ? args.last : {} [:table_name] ||= name define_sub(, &block) else clause(name, *args) end end |
Instance Attribute Details
#clauses ⇒ Object (readonly)
these are also reserved words regarding SQL column names use esc_* prefix to circumvent any issues
19 20 21 |
# File 'lib/og/ez/condition.rb', line 19 def clauses @clauses end |
#inner ⇒ Object
Returns the value of attribute inner.
20 21 22 |
# File 'lib/og/ez/condition.rb', line 20 def inner @inner end |
#outer ⇒ Object
Returns the value of attribute outer.
21 22 23 |
# File 'lib/og/ez/condition.rb', line 21 def outer @outer end |
Instance Method Details
#<<(condition, outer = nil) ⇒ Object Also known as: sql_condition, add_sql, clone_from, append
Append a condition element, which can be one of the following:
-
String: raw sql string
-
ActiveRecord instance, for attribute or PK cloning
-
Condition or Clause with to_sql method and outer property
-
Array in ActiveRecord format [‘column = ?’, 2]
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/og/ez/condition.rb', line 113 def <<(condition, outer = nil) if condition.kind_of?(String) and not condition.to_s.empty? cond = SqlClause.new(condition) cond.outer = outer || :and @clauses << cond elsif condition.kind_of?(Og::EntityMixin) if condition.attributes[condition.class.primary_key].nil? condition.attributes.each { |k, v| clause([condition.class.table_name, k]) == v unless v.to_s.empty? } else clause([condition.class.table_name, condition.class.primary_key]) == condition.attributes[condition.class.primary_key] end else if condition.kind_of?(Condition) or condition.kind_of?(AbstractClause) logic = condition.outer if outer.nil? condition = condition.to_sql else logic = outer end if condition.kind_of?(Array) and not condition.empty? array_clause = ArrayClause.new(condition) array_clause.outer = logic @clauses << array_clause end end end |
#and_condition(*args, &block) ⇒ Object Also known as: all
Shortcut for adding a :and boolean joined subcondition
85 86 87 88 89 90 91 |
# File 'lib/og/ez/condition.rb', line 85 def and_condition(*args, &block) = args.last.is_a?(Hash) ? args.last : {} [:table_name] = args.first if args.first.kind_of? Symbol [:outer] ||= @outer [:inner] ||= :and define_sub(, &block) end |
#clause(name, *args) ⇒ Object
You can define clauses dynamicly using this method. It will take a clause and create the correct Clause object to process the conditions
56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/og/ez/condition.rb', line 56 def clause(name, *args) if name.kind_of?(Array) c = Clause.new(name.first, name.last) elsif args.last.kind_of?(Symbol) c = Clause.new(args.pop, name) else c = Clause.new(@table_name, name) end @clauses << c c end |
#define_sub(*args, &block) ⇒ Object Also known as: sub, condition
Create subcondition from a block, optionally specifying table_name, outer and inner. :outer determines how the subcondition is added to the condition, while :inner determines the internal ‘joining’ of conditions inside the subcondition. Both :inner & :outer defult to ‘AND’
72 73 74 75 76 77 78 |
# File 'lib/og/ez/condition.rb', line 72 def define_sub(*args, &block) = args.last.is_a?(Hash) ? args.last : {} [:table_name] = args.first if args.first.kind_of? Symbol [:table_name] ||= @table_name cond = Condition.new(, &block) self << cond end |
#or_condition(*args, &block) ⇒ Object Also known as: any
Shortcut for adding a :or boolean joined subcondition
97 98 99 100 101 102 103 |
# File 'lib/og/ez/condition.rb', line 97 def or_condition(*args, &block) = args.last.is_a?(Hash) ? args.last : {} [:table_name] = args.first if args.first.kind_of? Symbol [:outer] ||= @outer [:inner] ||= :or define_sub(, &block) end |
#to_sql(logic = @inner) ⇒ Object
Loop over all Clause onjects in @clauses array and call to_sql on each instance. Then join the queries and params into the :conditions array with logic defaulting to AND. Subqueries are joined together using their individual outer property setting if present. Also defaults to AND.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/og/ez/condition.rb', line 154 def to_sql(logic=@inner) params = []; query = [] @clauses.each do |cv| q, p, e = cv.to_sql unless q.to_s.empty? logic = cv.outer ? cv.outer : logic logic = logic.to_s.upcase logic = 'AND NOT' if logic == 'NOT' query << logic unless query.empty? query << q if cv.test == :in params << p if p.respond_to?(:map) elsif p.kind_of?(Array) p.flatten! unless q =~ /IN/ params += p else params << p unless p.nil? params << e unless e.nil? end end end [query.join(' '), *params ] end |