Class: Spider::Model::Condition
- Defined in:
- lib/spiderfw/model/condition.rb
Overview
The Condition behaves like a ModelHash, and as such contains key-value pairs: a simple equality condition can be set with
condition[:element_name] = value
The Condition object also holds comparisons: a comparison different from equality can be set with
condition.set(:element_name, '>', value)
Finally, it contains subconditions, which can be added with
conditions << subcondition
Subconditions will be created automatically when using #set twice on the same element. If you want to change the condition, use #delete and set it again.
Conditions also support an SQL-like block syntax for setting conditions:
books_condition = Condition.new{ |book|
((book.year < 1970) | (book.price > 1000)) & (book..name .like 'John')
}
The Condition object, like the Request, doesn’t hold a reference to a model; so no check will be made that the conditions elements are meaningful.
Instance Attribute Summary collapse
-
#comparisons ⇒ Hash
readonly
An hash of comparisons for each element name.
-
#conjunct ⇒ Condition
A pointer to the last Condition used in condition blocks.
-
#conjunction ⇒ Symbol
The top level conjunction for the Condition (:or or :and; new Conditions are initialized with :or).
-
#polymorph ⇒ Class<BaseModel]
Polymorph model: used to tell the mapper the condition is on a subclass of the queried model.
-
#subconditions ⇒ Array
readonly
An Array of subconditions.
Class Method Summary collapse
-
.and(*params, &proc) ⇒ Condition
Instantiates a Condition with :and conjunction.
-
.comparison_operators_regexp ⇒ Regexp
Regexp to parse comparison operators.
-
.conj(conjunction, a, b) ⇒ Object
Used by Condition.and and Condition.or methods.
-
.no_conjunction(*params, &proc) ⇒ Condition
Instantiates a Condition with no conjunction.
-
.or(*params, &proc) ⇒ Condition
Instantiates a Condition with :or conjunction.
Instance Method Summary collapse
-
#+(condition) ⇒ Condition
Returns the result of merging the condition with another one (does not modify the original condition).
-
#<<(condition) ⇒ void
Adds a subcondtion.
-
#==(other) ⇒ bool
True if the two conditions have the same comparisions and conjunction.
-
#[](key) ⇒ Object
Gets the value of a condition.
-
#[]=(key, value) ⇒ self
Sets an equality comparison.
-
#all_each_with_comparison ⇒ void
Yields each key, value and comparison, for this condition and its subconditions.
-
#and(other = nil, &proc) ⇒ Condition
(also: #&, #AND)
Joins the condition to another with an “and” conjunction.
-
#clone ⇒ Condition
Returns a deep copy.
-
#conditions_array ⇒ Array
An array of all conditions, expressed as [key, value, comparison].
-
#conditions_for(*element_names) ⇒ Array
Returns, from self and subconditions, all those who define a condition for one of the given element names.
-
#conj(conjunction, other = nil, &proc) ⇒ Condition
Returns the conjunction with another condition.
-
#delete(field) ⇒ Array
Deletes a field from the Condition.
-
#each_with_comparison ⇒ Object
Yields each key, value and comparison.
-
#empty? ⇒ bool
True if there are no comparisons and no subconditions.
-
#eql?(other) ⇒ bool
See #==.
-
#get_deep_obj ⇒ Condition
See #ModelHash.get_deep_obj.
-
#hash ⇒ String
Keying hash.
-
#hash_clone ⇒ Object
Alias for Hash#clone.
-
#hash_empty? ⇒ Object
:nodoc:.
-
#hash_replace ⇒ Object
Alias to the original Hash#replace.
-
#hash_set ⇒ Object
Original hash value assignment.
-
#initialize(*params, &proc) ⇒ Condition
constructor
Instantiates a new Condition, with :and conjunction.
-
#inspect ⇒ String
A String representation of the condition.
-
#or(other = nil, &proc) ⇒ Condition
(also: #|, #OR)
Joins the condition to another with an “or” conjunction.
-
#parse_block(&proc) ⇒ Object
Parses a condition block.
-
#polymorphs ⇒ Array
An array of polymorphic conditions.
-
#primary_keys_only?(model) ⇒ bool
True if the condition has only primary keys for the given model.
-
#range(field, lower, upper) ⇒ self
Adds a range condition.
-
#replace(other) ⇒ self
Replace all the content of this Condition with another one.
-
#set(field, comparison, value) ⇒ self
Adds a single condition for an element.
-
#simplify ⇒ self
Traverses the tree removing useless conditions.
-
#uniq! ⇒ Object
Removes duplicate subcondtions.
Constructor Details
#initialize(*params, &proc) ⇒ Condition
Instantiates a new Condition, with :and conjunction. If given a Hash, will set all keys = values. If given multiple params, will convert each to a Condition if needed, and append them to the returned instance. If a block is given, it will be processed by #parse_block
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/spiderfw/model/condition.rb', line 108 def initialize(*params, &proc) @conjunction = :and @comparisons = {} @subconditions = [] params.reject!{ |p| p.nil? } if (params.length == 1 && params[0].is_a?(Hash) && !params[0].is_a?(Condition)) params[0].each do |k, v| set(k, '=', v) end else # FIXME: must have an instantiate method params.each{ |item| self << (item.is_a?(self.class) ? item : self.class.new(item)) } end parse_block(&proc) if (block_given?) end |
Instance Attribute Details
#comparisons ⇒ Hash (readonly)
An hash of comparisons for each element name
32 33 34 |
# File 'lib/spiderfw/model/condition.rb', line 32 def comparisons @comparisons end |
#conjunct ⇒ Condition
A pointer to the last Condition used in condition blocks
39 40 41 |
# File 'lib/spiderfw/model/condition.rb', line 39 def conjunct @conjunct end |
#conjunction ⇒ Symbol
The top level conjunction for the Condition (:or or :and; new Conditions are initialized with :or)
26 27 28 |
# File 'lib/spiderfw/model/condition.rb', line 26 def conjunction @conjunction end |
#polymorph ⇒ Class<BaseModel]
Polymorph model: used to tell the mapper the condition is on a subclass of the queried model.
29 30 31 |
# File 'lib/spiderfw/model/condition.rb', line 29 def polymorph @polymorph end |
#subconditions ⇒ Array (readonly)
An Array of subconditions
35 36 37 |
# File 'lib/spiderfw/model/condition.rb', line 35 def subconditions @subconditions end |
Class Method Details
.and(*params, &proc) ⇒ Condition
Instantiates a Condition with :and conjunction. See Condition.new for arguments.
79 80 81 82 83 |
# File 'lib/spiderfw/model/condition.rb', line 79 def self.and(*params, &proc) c = self.new(*params, &proc) c.conjunction = :and return c end |
.comparison_operators_regexp ⇒ Regexp
Regexp to parse comparison operators
60 61 62 |
# File 'lib/spiderfw/model/condition.rb', line 60 def self.comparison_operators_regexp @comparison_operators_regexp end |
.conj(conjunction, a, b) ⇒ Object
69 70 71 72 73 74 |
# File 'lib/spiderfw/model/condition.rb', line 69 def self.conj(conjunction, a, b) # :nodoc: c = Condition.new c.conjunction = conjunction c << a c << b end |
.no_conjunction(*params, &proc) ⇒ Condition
Instantiates a Condition with no conjunction. See Condition.new for arguments.
97 98 99 100 101 |
# File 'lib/spiderfw/model/condition.rb', line 97 def self.no_conjunction(*params, &proc) c = self.new(*params, &proc) c.conjunction = nil return c end |
.or(*params, &proc) ⇒ Condition
Instantiates a Condition with :or conjunction. See Condition.new for arguments.
88 89 90 91 92 |
# File 'lib/spiderfw/model/condition.rb', line 88 def self.or(*params, &proc) c = self.new(*params, &proc) c.conjunction = :or return c end |
Instance Method Details
#+(condition) ⇒ Condition
Returns the result of merging the condition with another one (does not modify the original condition).
186 187 188 189 190 191 192 193 |
# File 'lib/spiderfw/model/condition.rb', line 186 def +(condition) res = self.clone @subconditions += condition.subconditions condition.each_with_comparison do |k, v, c| res.set(k, v, c) end return res end |
#<<(condition) ⇒ void
This method returns an undefined value.
Adds a subcondtion.
198 199 200 201 202 203 204 205 206 207 |
# File 'lib/spiderfw/model/condition.rb', line 198 def <<(condition) if (condition.class == self.class) @subconditions << condition elsif (condition.is_a?(Hash)) @subconditions << self.class.new(condition) elsif (condition.class == String) key, val, comparison = parse_comparison(condition) set(key, val, comparison) end end |
#==(other) ⇒ bool
Returns True if the two conditions have the same comparisions and conjunction.
387 388 389 390 391 392 393 394 395 |
# File 'lib/spiderfw/model/condition.rb', line 387 def ==(other) return false unless other.class == self.class return false unless super return false unless @subconditions == other.subconditions return false unless @comparisons == other.comparisons return false unless @polymorph == other.polymorph return false unless @conjunction == other.conjunction return true end |
#[](key) ⇒ Object
Gets the value of a condition
261 262 263 264 265 266 |
# File 'lib/spiderfw/model/condition.rb', line 261 def [](key) # TODO: deep key = key.name if key.is_a?(Element) key = key.to_sym if key.respond_to?(:to_sym) # might be a QueryFunc super(key) end |
#[]=(key, value) ⇒ self
Sets an equality comparison.
Equivalent to #set(key, ‘=’, value)
254 255 256 |
# File 'lib/spiderfw/model/condition.rb', line 254 def []=(key, value) set(key, '=', value) end |
#all_each_with_comparison ⇒ void
This method returns an undefined value.
Yields each key, value and comparison, for this condition and its subconditions
170 171 172 173 174 175 |
# File 'lib/spiderfw/model/condition.rb', line 170 def all_each_with_comparison self.each_with_comparison{ |k, v, c| yield k, v, c } @subconditions.each do |sub| sub.all_each_with_comparison{ |k, v, c| yield k, v, c } end end |
#and(other = nil, &proc) ⇒ Condition Also known as: &, AND
Joins the condition to another with an “and” conjunction. See #conj.
352 353 354 |
# File 'lib/spiderfw/model/condition.rb', line 352 def and(other=nil, &proc) return conj(:and, other, &proc) end |
#clone ⇒ Condition
Returns a deep copy.
419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/spiderfw/model/condition.rb', line 419 def clone c = self.class.new c.conjunction = @conjunction c.polymorph = @polymorph self.each_with_comparison do |key, val, comparison| c.set(key, comparison, val) end @subconditions.each do |sub| c << sub.clone end return c end |
#conditions_array ⇒ Array
Returns An array of all conditions, expressed as [key, value, comparison].
152 153 154 155 156 157 |
# File 'lib/spiderfw/model/condition.rb', line 152 def conditions_array self.hash_clone.map do |k, v| k = k.to_sym if k.respond_to?(:to_sym) [k, v, (@comparisons[k] || '==')] end end |
#conditions_for(*element_names) ⇒ Array
Returns, from self and subconditions, all those who define a condition for one of the given element names.
453 454 455 456 457 458 459 460 461 462 463 |
# File 'lib/spiderfw/model/condition.rb', line 453 def conditions_for(*element_names) conds = [] element_names.each do |el| if self.key?(el) conds << self break end end @subconditions.map{ |s| s.conditions_for(*element_names) }.each{ |c| conds += c } conds end |
#conj(conjunction, other = nil, &proc) ⇒ Condition
Returns the conjunction with another condition. If this condition already has the required conjunction, the other will be added as a subcondition; otherwise, a new condition will be created and both will be added to it.
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/spiderfw/model/condition.rb', line 320 def conj(conjunction, other=nil, &proc) self.conjunction = conjunction if (!self.conjunction) if (self.conjunction == conjunction) c = self else c = Condition.new c.conjunction = conjunction c << self end if (!other && proc) other = Condition.new(&proc) end c << other other.conjunct = true return c end |
#delete(field) ⇒ Array
Deletes a field from the Condition.
283 284 285 286 287 288 289 290 |
# File 'lib/spiderfw/model/condition.rb', line 283 def delete(field) field = field.to_sym return nil unless self[field] || @comparisons[field] cur = [self[field], @comparisons[field]] super @comparisons.delete(field) cur end |
#each_with_comparison ⇒ Object
Yields each key, value and comparison.
161 162 163 164 165 166 |
# File 'lib/spiderfw/model/condition.rb', line 161 def each_with_comparison self.each do |k, v| k = k.to_sym if k.respond_to?(:to_sym) yield k, v, @comparisons[k] || '=' end end |
#empty? ⇒ bool
True if there are no comparisons and no subconditions.
362 363 364 365 366 367 368 |
# File 'lib/spiderfw/model/condition.rb', line 362 def empty? return false unless super @subconditions.each do |sub| return false unless sub.empty? end return true end |
#eql?(other) ⇒ bool
Returns See #==.
398 399 400 |
# File 'lib/spiderfw/model/condition.rb', line 398 def eql?(other) self == other end |
#get_deep_obj ⇒ Condition
See #ModelHash.get_deep_obj
45 46 47 48 49 |
# File 'lib/spiderfw/model/condition.rb', line 45 def get_deep_obj # :nodoc: c = self.class.new c.conjunction = @conjunction return c end |
#hash ⇒ String
Returns Keying hash.
403 404 405 |
# File 'lib/spiderfw/model/condition.rb', line 403 def hash ([self.keys, self.values, @comparisons.values, @polymorph] + @subconditions.map{ |s| s.hash}).hash end |
#hash_clone ⇒ Object
Alias for Hash#clone
415 |
# File 'lib/spiderfw/model/condition.rb', line 415 alias :hash_clone :clone |
#hash_empty? ⇒ Object
:nodoc:
358 |
# File 'lib/spiderfw/model/condition.rb', line 358 alias :hash_empty? :empty? |
#hash_replace ⇒ Object
Alias to the original Hash#replace
371 |
# File 'lib/spiderfw/model/condition.rb', line 371 alias :hash_replace :replace |
#hash_set ⇒ Object
Original hash value assignment
41 |
# File 'lib/spiderfw/model/condition.rb', line 41 alias :hash_set :[]= |
#inspect ⇒ String
Returns A String representation of the condition.
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/spiderfw/model/condition.rb', line 293 def inspect str = "" cnt = 0 each do |key, value| str += " #{@conjunction} " if cnt > 0 cnt += 1 comparison = @comparisons[key] || '=' cond = "#{comparison} #{value.inspect}" str += "#{key.inspect} #{cond}" end #str += ' [raw:'+raw.inspect+']' unless raw.empty? first = true if @subconditions.length > 0 str += ' '+@conjunction.to_s+' ' if str.length > 0 str += @subconditions.map{ |sub| sub.inspect }.reject{ |sub| sub.empty? }.join(' '+@conjunction.to_s+' ') end str = "(#{str})" if cnt + @subconditions.length > 1 return str end |
#or(other = nil, &proc) ⇒ Condition Also known as: |, OR
Joins the condition to another with an “or” conjunction. See #conj.
342 343 344 |
# File 'lib/spiderfw/model/condition.rb', line 342 def or(other=nil, &proc) return conj(:or, other, &proc) end |
#parse_block(&proc) ⇒ Object
Parses a condition block. Inside the block, an SQL-like language can be used.
Example:
condition.parse_block{ (element1 == val1) & ( (element2 > 'some string') | (element3 .not nil) ) }
All comparisons must be parenthesized; and/or conjunctions are expressed with a single &/|.
Available comparisions are: ==, >, <, >=, <=, .not, .like, .ilike (case insensitive like).
Note: for .like and .ilike comparisons, the SQL ‘%’ syntax must be used.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/spiderfw/model/condition.rb', line 136 def parse_block(&proc) res = nil if proc.arity == 1 res = proc.call(ConditionContext.new) else context = eval "self", proc.binding res = context.dup.extend(ConditionMixin).instance_eval(&proc) end self.replace(res) @conjunction = res.conjunction @comparisons = res.comparisons @subconditions = res.subconditions @polymorph = res.polymorph end |
#polymorphs ⇒ Array
Returns An array of polymorphic conditions.
444 445 446 447 448 |
# File 'lib/spiderfw/model/condition.rb', line 444 def polymorphs pol = [] pol << @polymorph if @polymorph return pol + @subconditions.inject([]){ |arr, s| arr += s.polymorphs } end |
#primary_keys_only?(model) ⇒ bool
Returns True if the condition has only primary keys for the given model.
179 180 181 |
# File 'lib/spiderfw/model/condition.rb', line 179 def primary_keys_only?(model) self.select{ |key, value| !model.elements[key] || !model.elements[key].primary_key? }.empty? end |
#range(field, lower, upper) ⇒ self
Adds a range condition. This creates a subcondition with >= and <= conditions.
273 274 275 276 277 278 |
# File 'lib/spiderfw/model/condition.rb', line 273 def range(field, lower, upper) c = self.class.and c.set(field, '>=', lower) c.set(field, '<=', upper) self << c end |
#replace(other) ⇒ self
Replace all the content of this Condition with another one.
376 377 378 379 380 381 382 383 |
# File 'lib/spiderfw/model/condition.rb', line 376 def replace(other) hash_replace(other) @subconditions = other.subconditions @conjunction = other.conjunction @polymorph = other.polymorph @comparisons = other.comparisons self end |
#set(field, comparison, value) ⇒ self
Adds a single condition for an element
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/spiderfw/model/condition.rb', line 214 def set(field, comparison, value) if value.is_a?(QuerySet) value = value.to_a end if value.is_a?(Array) && comparison != 'between' multi_cond = comparison == '<>' ? self.class.and : self.class.or value.uniq.each do |v| multi_cond.set(field, comparison, v) end @subconditions << multi_cond return self end parts = [] unless field.is_a?(Spider::QueryFuncs::Function) field = field.to_s parts = field.split('.', 2) debugger if parts[0].blank? parts[0] = parts[0].to_sym field = field.to_sym unless parts[1] end if (parts[1]) hash_set(parts[0], get_deep_obj()) unless self[parts[0]] self[parts[0]].set(parts[1], comparison, value) elsif (self[field]) c = Condition.new c.set(field, comparison, value) @subconditions << c else hash_set(field, value) @comparisons[field] = comparison end return self end |
#simplify ⇒ self
Traverses the tree removing useless conditions.
434 435 436 437 438 439 440 441 |
# File 'lib/spiderfw/model/condition.rb', line 434 def simplify @subconditions.each{ |sub| sub.simplify } if (hash_empty? && @subconditions.length == 1) self.replace(@subconditions[0]) end @subconditions.uniq! return self end |
#uniq! ⇒ Object
Removes duplicate subcondtions.
409 410 411 412 |
# File 'lib/spiderfw/model/condition.rb', line 409 def uniq! @subconditions.uniq! self end |