Class: ScopedSearch::QueryBuilder
- Inherits:
-
Object
- Object
- ScopedSearch::QueryBuilder
- Defined in:
- lib/scoped_search/query_builder.rb
Defined Under Namespace
Constant Summary collapse
- SQL_OPERATORS =
{ :eq =>'=', :ne => '<>', :like => 'LIKE', :unlike => 'NOT LIKE', :gt => '>', :lt =>'<', :lte => '<=', :gte => '>=' }
Instance Attribute Summary collapse
-
#ast ⇒ Object
readonly
Returns the value of attribute ast.
-
#definition ⇒ Object
readonly
Returns the value of attribute definition.
Class Method Summary collapse
-
.build_query(definition, query) ⇒ Object
Creates a find parameter hash given a class, and query string.
-
.datetime_test(field, operator, value) {|:parameter, timestamp| ... } ⇒ Object
Perform a comparison between a field and a Date(Time) value.
-
.parse_temporal(value) ⇒ Object
Try to parse a string as a datetime.
-
.sql_operator(operator, field) ⇒ Object
Return the SQL operator to use.
-
.sql_test(field, operator, value, &block) ⇒ Object
Generates a simple SQL test expression, for a field and value using an operator.
Instance Method Summary collapse
-
#build_find_params ⇒ Object
Actually builds the find parameters.
-
#initialize(definition, ast) ⇒ QueryBuilder
constructor
Initializes the instance by setting the relevant parameters.
Constructor Details
#initialize(definition, ast) ⇒ QueryBuilder
Initializes the instance by setting the relevant parameters
20 21 22 |
# File 'lib/scoped_search/query_builder.rb', line 20 def initialize(definition, ast) @definition, @ast = definition, ast end |
Instance Attribute Details
#ast ⇒ Object (readonly)
Returns the value of attribute ast.
5 6 7 |
# File 'lib/scoped_search/query_builder.rb', line 5 def ast @ast end |
#definition ⇒ Object (readonly)
Returns the value of attribute definition.
5 6 7 |
# File 'lib/scoped_search/query_builder.rb', line 5 def definition @definition end |
Class Method Details
.build_query(definition, query) ⇒ Object
Creates a find parameter hash given a class, and query string.
8 9 10 11 12 13 14 15 16 17 |
# File 'lib/scoped_search/query_builder.rb', line 8 def self.build_query(definition, query) # Return all record when an empty search string is given if !query.kind_of?(String) || query.strip.blank? return { :conditions => nil } elsif query.kind_of?(ScopedSearch::QueryLanguage::AST::Node) return self.new(definition, query).build_find_params else return self.new(definition, ScopedSearch::QueryLanguage::Compiler.parse(query)).build_find_params end end |
.datetime_test(field, operator, value) {|:parameter, timestamp| ... } ⇒ Object
Perform a comparison between a field and a Date(Time) value. Makes sure the date is valid and adjust the comparison in some cases to return more logical results
62 63 64 65 66 67 68 69 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 |
# File 'lib/scoped_search/query_builder.rb', line 62 def self.datetime_test(field, operator, value, &block) # Parse the value as a date/time and ignore invalid timestamps = parse_temporal(value) return nil unless = Date.parse(.strftime('%Y-%m-%d')) if field.date? # Check for the case that a date-only value is given as search keyword, # but the field is of datetime type. Change the comparison to return # more logical results. if .day_fraction == 0 && field.datetime? if [:eq, :ne].include?(operator) # Instead of looking for an exact (non-)match, look for dates that # fall inside/outside the range of timestamps of that day. yield(:parameter, ) yield(:parameter, + 1) negate = (operator == :ne) ? 'NOT' : '' field_sql = field.to_sql(operator, &block) return "#{negate}(#{field_sql} >= ? AND #{field_sql} < ?)" elsif operator == :gt # Make sure timestamps on the given date are not included in the results # by moving the date to the next day. += 1 operator = :gte elsif operator == :lte # Make sure the timestamps of the given date are included by moving the # date to the next date. += 1 operator = :lt end end # Yield the timestamp and return the SQL test yield(:parameter, ) "#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?" end |
.parse_temporal(value) ⇒ Object
Try to parse a string as a datetime.
116 117 118 |
# File 'lib/scoped_search/query_builder.rb', line 116 def self.parse_temporal(value) DateTime.parse(value, true) rescue nil end |
.sql_operator(operator, field) ⇒ Object
Return the SQL operator to use
55 56 57 |
# File 'lib/scoped_search/query_builder.rb', line 55 def self.sql_operator(operator, field) SQL_OPERATORS[operator] end |
.sql_test(field, operator, value, &block) ⇒ Object
Generates a simple SQL test expression, for a field and value using an operator.
103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/scoped_search/query_builder.rb', line 103 def self.sql_test(field, operator, value, &block) if [:like, :unlike].include?(operator) && value !~ /^\%/ && value !~ /\%$/ yield(:parameter, "%#{value}%") return "#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?" elsif field.temporal? return datetime_test(field, operator, value, &block) else yield(:parameter, value) return "#{field.to_sql(operator, &block)} #{self.sql_operator(operator, field)} ?" end end |
Instance Method Details
#build_find_params ⇒ Object
Actually builds the find parameters
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/scoped_search/query_builder.rb', line 25 def build_find_params parameters = [] includes = [] # Build SQL WHERE clause using the AST sql = @ast.to_sql(definition) do |notification, value| # Handle the notifications encountered during the SQL generation: # Store the parameters, includes, etc so that they can be added to # the find-hash later on. case notification when :parameter then parameters << value when :include then includes << value else raise ScopedSearch::QueryNotSupported, "Cannot handle #{notification.inspect}: #{value.inspect}" end end # Build hash for ActiveRecord::Base#find for the named scope find_attributes = {} find_attributes[:conditions] = [sql] + parameters unless sql.nil? find_attributes[:include] = includes.uniq unless includes.empty? # p find_attributes # Uncomment for debugging return find_attributes end |