birddog 0.0.8 → 0.0.9.p1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/birddog.gemspec +0 -1
 - data/lib/birddog/birddog.rb +46 -34
 - data/lib/birddog/field_conditions.rb +53 -33
 - data/lib/birddog/scope_builder.rb +26 -0
 - data/lib/birddog/version.rb +1 -1
 - data/lib/birddog.rb +0 -5
 - data/specs/birddog_spec.rb +0 -5
 - data/specs/spec_helper.rb +21 -28
 - metadata +21 -34
 
    
        data/birddog.gemspec
    CHANGED
    
    
    
        data/lib/birddog/birddog.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'birddog/scope_builder'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Birddog
         
     | 
| 
       2 
4 
     | 
    
         | 
| 
       3 
5 
     | 
    
         
             
              def self.included(base)
         
     | 
| 
         @@ -23,7 +25,7 @@ module Birddog 
     | 
|
| 
       23 
25 
     | 
    
         | 
| 
       24 
26 
     | 
    
         
             
                def field(name, options={}, &mapping)
         
     | 
| 
       25 
27 
     | 
    
         
             
                  @fields[name] = field = {
         
     | 
| 
       26 
     | 
    
         
            -
                    :attribute       => options.fetch(:attribute,  
     | 
| 
      
 28 
     | 
    
         
            +
                    :attribute       => field_attribute(name, options.fetch(:attribute, nil), options.fetch(:aggregate, nil)),
         
     | 
| 
       27 
29 
     | 
    
         
             
                    :cast            => options.fetch(:cast, false),
         
     | 
| 
       28 
30 
     | 
    
         
             
                    :type            => options.fetch(:type, :string),
         
     | 
| 
       29 
31 
     | 
    
         
             
                    :case_sensitive  => options.fetch(:case_sensitive, true),
         
     | 
| 
         @@ -47,27 +49,36 @@ module Birddog 
     | 
|
| 
       47 
49 
     | 
    
         
             
                  aggregate?(name) ? define_aggregate_field(name, @fields[name]) : define_field(name, @fields[name])
         
     | 
| 
       48 
50 
     | 
    
         
             
                end
         
     | 
| 
       49 
51 
     | 
    
         | 
| 
      
 52 
     | 
    
         
            +
                def aggregatable(*fields)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  fields.flatten.compact.uniq.each do |agg_field|
         
     | 
| 
      
 54 
     | 
    
         
            +
                    averagable(agg_field)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    minimumable(agg_field)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    maximumable(agg_field)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    sumable(agg_field)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
       50 
61 
     | 
    
         
             
                def averagable(*fields)
         
     | 
| 
       51 
     | 
    
         
            -
                  fields.flatten.each do |avg_field|
         
     | 
| 
       52 
     | 
    
         
            -
                    @averagable << avg_field
         
     | 
| 
      
 62 
     | 
    
         
            +
                  fields.flatten.compact.uniq.each do |avg_field|
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @averagable << avg_field unless @averagable.include?(avg_field)
         
     | 
| 
       53 
64 
     | 
    
         
             
                  end
         
     | 
| 
       54 
65 
     | 
    
         
             
                end
         
     | 
| 
       55 
66 
     | 
    
         | 
| 
       56 
67 
     | 
    
         
             
                def minimumable(*fields)
         
     | 
| 
       57 
     | 
    
         
            -
                  fields.flatten.each do |min_field|
         
     | 
| 
       58 
     | 
    
         
            -
                    @minimumable << min_field
         
     | 
| 
      
 68 
     | 
    
         
            +
                  fields.flatten.compact.uniq.each do |min_field|
         
     | 
| 
      
 69 
     | 
    
         
            +
                    @minimumable << min_field unless @minimumable.include?(min_field)
         
     | 
| 
       59 
70 
     | 
    
         
             
                  end
         
     | 
| 
       60 
71 
     | 
    
         
             
                end
         
     | 
| 
       61 
72 
     | 
    
         | 
| 
       62 
73 
     | 
    
         
             
                def maximumable(*fields)
         
     | 
| 
       63 
     | 
    
         
            -
                  fields.flatten.each do |max_field|
         
     | 
| 
       64 
     | 
    
         
            -
                    @maximumable << max_field 
         
     | 
| 
      
 74 
     | 
    
         
            +
                  fields.flatten.compact.uniq.each do |max_field|
         
     | 
| 
      
 75 
     | 
    
         
            +
                    @maximumable << max_field unless @maximumable.include?(max_field)
         
     | 
| 
       65 
76 
     | 
    
         
             
                  end
         
     | 
| 
       66 
77 
     | 
    
         
             
                end
         
     | 
| 
       67 
78 
     | 
    
         | 
| 
       68 
79 
     | 
    
         
             
                def sumable(*fields)
         
     | 
| 
       69 
     | 
    
         
            -
                  fields.flatten.each do |sum_field|
         
     | 
| 
       70 
     | 
    
         
            -
                    @sumable << sum_field
         
     | 
| 
      
 80 
     | 
    
         
            +
                  fields.flatten.compact.uniq.each do |sum_field|
         
     | 
| 
      
 81 
     | 
    
         
            +
                    @sumable << sum_field unless @sumable.include?(sum_field)
         
     | 
| 
       71 
82 
     | 
    
         
             
                  end
         
     | 
| 
       72 
83 
     | 
    
         
             
                end
         
     | 
| 
       73 
84 
     | 
    
         | 
| 
         @@ -76,23 +87,26 @@ module Birddog 
     | 
|
| 
       76 
87 
     | 
    
         
             
                end
         
     | 
| 
       77 
88 
     | 
    
         | 
| 
       78 
89 
     | 
    
         
             
                def search(query)
         
     | 
| 
       79 
     | 
    
         
            -
                   
     | 
| 
       80 
     | 
    
         
            -
                   
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                    scope_for(model, key, value)
         
     | 
| 
       83 
     | 
    
         
            -
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  key, value = tokenize(query)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  key, value = "text_search", key if value.nil?
         
     | 
| 
      
 92 
     | 
    
         
            +
                  scope_for(@model, key, value)
         
     | 
| 
       84 
93 
     | 
    
         
             
                end
         
     | 
| 
       85 
94 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                 
     | 
| 
       87 
     | 
    
         
            -
                  options = fields.extract_options!
         
     | 
| 
       88 
     | 
    
         
            -
                  fields = fields.map { |f| "LOWER(#{f}) LIKE :value" }.join(" OR ")
         
     | 
| 
      
 95 
     | 
    
         
            +
                ################## PRIVATES ####################
         
     | 
| 
       89 
96 
     | 
    
         | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                def aggregate_and_aliased?(aggregate)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  aggregate && aggregate.respond_to?(:alias) && aggregate.alias
         
     | 
| 
       93 
99 
     | 
    
         
             
                end
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
      
 100 
     | 
    
         
            +
                private :aggregate_and_aliased?
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                def field_attribute(name, val, aggregate)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  val = name.to_sym unless val
         
     | 
| 
      
 104 
     | 
    
         
            +
                  val = ::Arel::Nodes::SqlLiteral.new(aggregate.alias) if aggregate_and_aliased?(aggregate)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  val = @model.arel_table[val] if val.is_a?(Symbol)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  val = ::Arel::Nodes::SqlLiteral.new(val) if val.is_a?(String)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  return val
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
                private :field_attribute
         
     | 
| 
       96 
110 
     | 
    
         | 
| 
       97 
111 
     | 
    
         
             
                def conditional?(value)
         
     | 
| 
       98 
112 
     | 
    
         
             
                  value.index(/[<>=]/) != nil   
         
     | 
| 
         @@ -103,18 +117,16 @@ module Birddog 
     | 
|
| 
       103 
117 
     | 
    
         
             
                  field[:options].merge!(:select => field[:aggregate])
         
     | 
| 
       104 
118 
     | 
    
         | 
| 
       105 
119 
     | 
    
         
             
                  define_scope(name) do |value|
         
     | 
| 
       106 
     | 
    
         
            -
                     
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                    else
         
     | 
| 
       109 
     | 
    
         
            -
                      field[:options]
         
     | 
| 
       110 
     | 
    
         
            -
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
                    current_scope = ::Birddog::ScopeBuilder.build(@model, field[:options])
         
     | 
| 
      
 121 
     | 
    
         
            +
                    conditional?(value) ? setup_conditions(current_scope, field, value) : current_scope
         
     | 
| 
       111 
122 
     | 
    
         
             
                  end
         
     | 
| 
       112 
123 
     | 
    
         
             
                end
         
     | 
| 
       113 
124 
     | 
    
         
             
                private :define_aggregate_field
         
     | 
| 
       114 
125 
     | 
    
         | 
| 
       115 
126 
     | 
    
         
             
                def define_field(name, field)
         
     | 
| 
       116 
127 
     | 
    
         
             
                  define_scope(name) do |value|
         
     | 
| 
       117 
     | 
    
         
            -
                    field[:options] 
     | 
| 
      
 128 
     | 
    
         
            +
                    current_scope = ::Birddog::ScopeBuilder.build(@model, field[:options])
         
     | 
| 
      
 129 
     | 
    
         
            +
                    setup_conditions(current_scope, field, value)
         
     | 
| 
       118 
130 
     | 
    
         
             
                  end
         
     | 
| 
       119 
131 
     | 
    
         
             
                end
         
     | 
| 
       120 
132 
     | 
    
         
             
                private :define_field
         
     | 
| 
         @@ -169,20 +181,20 @@ module Birddog 
     | 
|
| 
       169 
181 
     | 
    
         
             
                end
         
     | 
| 
       170 
182 
     | 
    
         
             
                private :parse_condition
         
     | 
| 
       171 
183 
     | 
    
         | 
| 
       172 
     | 
    
         
            -
                def setup_conditions(field, value)
         
     | 
| 
      
 184 
     | 
    
         
            +
                def setup_conditions(current_scope, field, value)
         
     | 
| 
       173 
185 
     | 
    
         
             
                  condition = parse_condition(value)
         
     | 
| 
       174 
186 
     | 
    
         
             
                  value = callable_or_cast(field, condition, value) 
         
     | 
| 
       175 
187 
     | 
    
         
             
                  value = field[:mapping].call(value)
         
     | 
| 
       176 
188 
     | 
    
         | 
| 
       177 
189 
     | 
    
         
             
                  case field[:type]
         
     | 
| 
       178 
190 
     | 
    
         
             
                  when :string then
         
     | 
| 
       179 
     | 
    
         
            -
                    conditions_for_string_search(field, value)
         
     | 
| 
      
 191 
     | 
    
         
            +
                    conditions_for_string_search(current_scope, field, condition, value)
         
     | 
| 
       180 
192 
     | 
    
         
             
                  when :float, :decimal, :integer then
         
     | 
| 
       181 
     | 
    
         
            -
                    conditions_for_numeric(field, condition, value)
         
     | 
| 
      
 193 
     | 
    
         
            +
                    conditions_for_numeric(current_scope, field, condition, value, field[:type])
         
     | 
| 
       182 
194 
     | 
    
         
             
                  when :date, :datetime, :time then 
         
     | 
| 
       183 
     | 
    
         
            -
                    conditions_for_date(field, condition, value)
         
     | 
| 
      
 195 
     | 
    
         
            +
                    conditions_for_date(current_scope, field, condition, value)
         
     | 
| 
       184 
196 
     | 
    
         
             
                  else
         
     | 
| 
       185 
     | 
    
         
            -
                     
     | 
| 
      
 197 
     | 
    
         
            +
                    current_scope.where(field[:attribute] => value)
         
     | 
| 
       186 
198 
     | 
    
         
             
                  end
         
     | 
| 
       187 
199 
     | 
    
         
             
                end
         
     | 
| 
       188 
200 
     | 
    
         
             
                private :setup_conditions
         
     | 
| 
         @@ -191,7 +203,7 @@ module Birddog 
     | 
|
| 
       191 
203 
     | 
    
         
             
                  split_tokens = query.split(":")
         
     | 
| 
       192 
204 
     | 
    
         
             
                  split_tokens.each { |tok| tok.strip! }
         
     | 
| 
       193 
205 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
                  [ 
     | 
| 
      
 206 
     | 
    
         
            +
                  [split_tokens.shift, split_tokens.join(":")]
         
     | 
| 
       195 
207 
     | 
    
         
             
                end
         
     | 
| 
       196 
208 
     | 
    
         
             
                private :tokenize
         
     | 
| 
       197 
209 
     | 
    
         | 
| 
         @@ -2,51 +2,71 @@ module Birddog 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
              module FieldConditions
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                 
     | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
       7 
     | 
    
         
            -
                   
     | 
| 
       8 
     | 
    
         
            -
                   
     | 
| 
       9 
     | 
    
         
            -
                }
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                def conditions_for_string_search(field, value)
         
     | 
| 
       12 
     | 
    
         
            -
                  search_con = " LIKE ? "
         
     | 
| 
       13 
     | 
    
         
            -
                  field_to_search = "lower(#{field[:attribute]})"
         
     | 
| 
       14 
     | 
    
         
            -
                  value_to_search = value.downcase
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
                  if field[:case_sensitive]
         
     | 
| 
       17 
     | 
    
         
            -
                    field_to_search = field[:attribute]
         
     | 
| 
       18 
     | 
    
         
            -
                    value_to_search = value
         
     | 
| 
       19 
     | 
    
         
            -
                  end
         
     | 
| 
      
 5 
     | 
    
         
            +
                def conditions_for_string_search(current_scope, field, condition, value)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  search_con = condition
         
     | 
| 
      
 7 
     | 
    
         
            +
                  strict_equality = (search_con == "==")
         
     | 
| 
      
 8 
     | 
    
         
            +
                  value_to_search = (value ? value.dup : nil)
         
     | 
| 
       20 
9 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                  if  
     | 
| 
       22 
     | 
    
         
            -
                     
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
      
 10 
     | 
    
         
            +
                  if !strict_equality
         
     | 
| 
      
 11 
     | 
    
         
            +
                    if field[:match_substring]
         
     | 
| 
      
 12 
     | 
    
         
            +
                      search_con = "=~"
         
     | 
| 
      
 13 
     | 
    
         
            +
                      value_to_search = "%#{value_to_search}%"
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
       24 
15 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                     
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
                    if field[:regex] && regexed?(value)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      # TODO check db driver to determine regex operator for DB (current is Postgres)
         
     | 
| 
      
 18 
     | 
    
         
            +
                      search_con = "=~"
         
     | 
| 
      
 19 
     | 
    
         
            +
                      value_to_search = value[1..value.size-2]
         
     | 
| 
      
 20 
     | 
    
         
            +
                    elsif field[:wildcard] && value_to_search.include?("*")
         
     | 
| 
      
 21 
     | 
    
         
            +
                      search_con = "=~"
         
     | 
| 
      
 22 
     | 
    
         
            +
                      value_to_search.gsub!(/[\*]/, "%")
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
       32 
24 
     | 
    
         
             
                  end
         
     | 
| 
       33 
25 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                  [  
     | 
| 
      
 26 
     | 
    
         
            +
                  conditionally_scoped(current_scope, field[:attribute], search_con, value_to_search, field[:aggregate])
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def conditions_for_date(current_scope, field, condition, value)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  conditionally_scoped(current_scope, field[:attribute], condition, value.value.strftime("%Y-%m-%d"), field[:aggregate])
         
     | 
| 
       35 
31 
     | 
    
         
             
                end
         
     | 
| 
       36 
32 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                def  
     | 
| 
       38 
     | 
    
         
            -
                   
     | 
| 
      
 33 
     | 
    
         
            +
                def conditions_for_numeric(current_scope, field, condition, value, field_type)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  conditionally_scoped(current_scope, field[:attribute], condition, cast_numeric(field_type, value), field[:aggregate], true)
         
     | 
| 
       39 
35 
     | 
    
         
             
                end
         
     | 
| 
       40 
36 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                def  
     | 
| 
       42 
     | 
    
         
            -
                   
     | 
| 
      
 37 
     | 
    
         
            +
                def cast_numeric(field_type, value)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  case field_type
         
     | 
| 
      
 39 
     | 
    
         
            +
                  when :integer then
         
     | 
| 
      
 40 
     | 
    
         
            +
                    value.to_i
         
     | 
| 
      
 41 
     | 
    
         
            +
                  else
         
     | 
| 
      
 42 
     | 
    
         
            +
                    value.to_f
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
       43 
45 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 46 
     | 
    
         
            +
                def conditionally_scoped(current_scope, field, condition, value, aggregate, is_numeric = false)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  having_or_where = (aggregate ? :having : :where)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  scope = case condition
         
     | 
| 
       45 
49 
     | 
    
         
             
                  when "=~", "~=" then
         
     | 
| 
       46 
     | 
    
         
            -
                     
     | 
| 
      
 50 
     | 
    
         
            +
                    if is_numeric
         
     | 
| 
      
 51 
     | 
    
         
            +
                      current_scope.__send__(having_or_where, field.gteq(value.floor).and(field.lt((value + 1).floor))) 
         
     | 
| 
      
 52 
     | 
    
         
            +
                    else
         
     | 
| 
      
 53 
     | 
    
         
            +
                      current_scope.__send__(having_or_where, field.matches(value))
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  when :<, "<" then
         
     | 
| 
      
 56 
     | 
    
         
            +
                    current_scope.__send__(having_or_where, field.lt(value))
         
     | 
| 
      
 57 
     | 
    
         
            +
                  when :>, ">" then
         
     | 
| 
      
 58 
     | 
    
         
            +
                    current_scope.__send__(having_or_where, field.gt(value))
         
     | 
| 
      
 59 
     | 
    
         
            +
                  when :<=, "<=", "=<" then
         
     | 
| 
      
 60 
     | 
    
         
            +
                    current_scope.__send__(having_or_where, field.lteq(value))
         
     | 
| 
      
 61 
     | 
    
         
            +
                  when :>=, ">=", "=>" then
         
     | 
| 
      
 62 
     | 
    
         
            +
                    current_scope.__send__(having_or_where, field.gteq(value))
         
     | 
| 
      
 63 
     | 
    
         
            +
                  when "=", "==" then
         
     | 
| 
      
 64 
     | 
    
         
            +
                    current_scope.__send__(having_or_where, field.eq(value))
         
     | 
| 
       47 
65 
     | 
    
         
             
                  else
         
     | 
| 
       48 
     | 
    
         
            -
                     
     | 
| 
      
 66 
     | 
    
         
            +
                    raise "#{condition} not defined for #{field}"
         
     | 
| 
       49 
67 
     | 
    
         
             
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  return scope
         
     | 
| 
       50 
70 
     | 
    
         
             
                end
         
     | 
| 
       51 
71 
     | 
    
         | 
| 
       52 
72 
     | 
    
         
             
                def regexed?(value)
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Birddog
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              class ScopeBuilder
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def self.build(model, scope_options)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  new(model, scope_options).build
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(model, scope_options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @options = scope_options
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @model = model
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def build
         
     | 
| 
      
 15 
     | 
    
         
            +
                  scope = @model.scoped
         
     | 
| 
      
 16 
     | 
    
         
            +
                  
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @options.each do |k, v|
         
     | 
| 
      
 18 
     | 
    
         
            +
                    scope = scope.__send__(k, v)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  
         
     | 
| 
      
 21 
     | 
    
         
            +
                  return scope
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
              
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/birddog/version.rb
    CHANGED
    
    
    
        data/lib/birddog.rb
    CHANGED
    
    | 
         @@ -17,11 +17,6 @@ 
     | 
|
| 
       17 
17 
     | 
    
         
             
            require 'chronic'
         
     | 
| 
       18 
18 
     | 
    
         
             
            require 'active_support/core_ext'
         
     | 
| 
       19 
19 
     | 
    
         
             
            require 'active_record'
         
     | 
| 
       20 
     | 
    
         
            -
            require 'squeel'
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
            Squeel.configure do |config|
         
     | 
| 
       23 
     | 
    
         
            -
              config.load_core_extensions :hash  
         
     | 
| 
       24 
     | 
    
         
            -
            end
         
     | 
| 
       25 
20 
     | 
    
         | 
| 
       26 
21 
     | 
    
         
             
            require "birddog/version"
         
     | 
| 
       27 
22 
     | 
    
         
             
            require "birddog/field_conditions"
         
     | 
    
        data/specs/birddog_spec.rb
    CHANGED
    
    | 
         @@ -36,11 +36,6 @@ describe Birddog::Birddog do #################### 
     | 
|
| 
       36 
36 
     | 
    
         
             
                User.scopes_for_query("last_name:Doe").size.must_equal(1)
         
     | 
| 
       37 
37 
     | 
    
         
             
              end
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
              it "can find using case insensitive search" do
         
     | 
| 
       40 
     | 
    
         
            -
                User.scopes_for_query("insensitive_last_name:doe").must_include(@john)
         
     | 
| 
       41 
     | 
    
         
            -
                User.scopes_for_query("insensitive_last_name:doe").size.must_equal(1)
         
     | 
| 
       42 
     | 
    
         
            -
              end
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
39 
     | 
    
         
             
              it "can find matching substrings" do
         
     | 
| 
       45 
40 
     | 
    
         
             
                User.scopes_for_query("substringed_last_name:oe").must_include(@john)
         
     | 
| 
       46 
41 
     | 
    
         
             
                User.scopes_for_query("substringed_last_name:oe").size.must_equal(1)
         
     | 
    
        data/specs/spec_helper.rb
    CHANGED
    
    | 
         @@ -30,6 +30,24 @@ ActiveRecord::Schema.define(:version => 1) do 
     | 
|
| 
       30 
30 
     | 
    
         
             
              end
         
     | 
| 
       31 
31 
     | 
    
         
             
            end
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
      
 33 
     | 
    
         
            +
            class Product < ActiveRecord::Base
         
     | 
| 
      
 34 
     | 
    
         
            +
              include Birddog
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              belongs_to :user
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              birddog do |search|
         
     | 
| 
      
 39 
     | 
    
         
            +
                search.aggregatable :value
         
     | 
| 
      
 40 
     | 
    
         
            +
                search.field :name, :regex => true, :wildcard => true
         
     | 
| 
      
 41 
     | 
    
         
            +
                search.field :cast_val, :type => :decimal, :cast => lambda { |v| v }, :attribute => :value
         
     | 
| 
      
 42 
     | 
    
         
            +
                search.field :value, :type => :decimal
         
     | 
| 
      
 43 
     | 
    
         
            +
                search.field :available, :type => :boolean
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                search.keyword :sort do |value|
         
     | 
| 
      
 46 
     | 
    
         
            +
                  order(search.fields[value.to_sym][:attribute].desc)
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
       33 
51 
     | 
    
         
             
            class User < ActiveRecord::Base
         
     | 
| 
       34 
52 
     | 
    
         
             
              include Birddog
         
     | 
| 
       35 
53 
     | 
    
         | 
| 
         @@ -39,9 +57,9 @@ class User < ActiveRecord::Base 
     | 
|
| 
       39 
57 
     | 
    
         
             
                search.field :first_name
         
     | 
| 
       40 
58 
     | 
    
         
             
                search.alias_field :name, :first_name
         
     | 
| 
       41 
59 
     | 
    
         
             
                search.field :last_name
         
     | 
| 
       42 
     | 
    
         
            -
                search.field :total_product_value, :type => :decimal, :aggregate =>  
     | 
| 
       43 
     | 
    
         
            -
                search.field :insensitive_last_name, :attribute =>  
     | 
| 
       44 
     | 
    
         
            -
                search.field :substringed_last_name, :attribute =>  
     | 
| 
      
 60 
     | 
    
         
            +
                search.field :total_product_value, :type => :decimal, :aggregate => Product.arel_table[:value].sum.as("total_product_value")
         
     | 
| 
      
 61 
     | 
    
         
            +
                search.field :insensitive_last_name, :attribute => arel_table[:last_name], :case_sensitive => false
         
     | 
| 
      
 62 
     | 
    
         
            +
                search.field :substringed_last_name, :attribute => arel_table[:last_name], :match_substring => true
         
     | 
| 
       45 
63 
     | 
    
         
             
                search.field :available_product, :type => :boolean,
         
     | 
| 
       46 
64 
     | 
    
         
             
                                                 :attribute => "products.available",
         
     | 
| 
       47 
65 
     | 
    
         
             
                                                 :joins => :products
         
     | 
| 
         @@ -51,30 +69,5 @@ class User < ActiveRecord::Base 
     | 
|
| 
       51 
69 
     | 
    
         
             
                    joins("LEFT OUTER JOIN products AS products ON (products.user_id = users.id)").
         
     | 
| 
       52 
70 
     | 
    
         
             
                    group(arel_table[:id])
         
     | 
| 
       53 
71 
     | 
    
         
             
                end
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                search.text_search "first_name", "last_name", "products.name", :include => :products
         
     | 
| 
       56 
     | 
    
         
            -
              end
         
     | 
| 
       57 
     | 
    
         
            -
            end
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
            class Product < ActiveRecord::Base
         
     | 
| 
       60 
     | 
    
         
            -
              include Birddog
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
              belongs_to :user
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
              birddog do |search|
         
     | 
| 
       65 
     | 
    
         
            -
                search.averagable :value
         
     | 
| 
       66 
     | 
    
         
            -
                search.minimumable :value
         
     | 
| 
       67 
     | 
    
         
            -
                search.maximumable :value
         
     | 
| 
       68 
     | 
    
         
            -
                search.sumable :value
         
     | 
| 
       69 
     | 
    
         
            -
                search.text_search "products.name", "products.value"
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                search.field :name, :regex => true, :wildcard => true
         
     | 
| 
       72 
     | 
    
         
            -
                search.field :cast_val, :type => :decimal, :cast => lambda { |v| v }, :attribute => :value
         
     | 
| 
       73 
     | 
    
         
            -
                search.field :value, :type => :decimal
         
     | 
| 
       74 
     | 
    
         
            -
                search.field :available, :type => :boolean
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
                search.keyword :sort do |value|
         
     | 
| 
       77 
     | 
    
         
            -
                  { :order => "#{search.fields[value.to_sym][:attribute]} DESC" }
         
     | 
| 
       78 
     | 
    
         
            -
                end
         
     | 
| 
       79 
72 
     | 
    
         
             
              end
         
     | 
| 
       80 
73 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,19 +1,19 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: birddog
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.0. 
     | 
| 
       5 
     | 
    
         
            -
              prerelease: 
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.9.p1
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 6
         
     | 
| 
       6 
6 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       7 
7 
     | 
    
         
             
            authors:
         
     | 
| 
       8 
8 
     | 
    
         
             
            - Brandon Dewitt
         
     | 
| 
       9 
9 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       10 
10 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       11 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       12 
     | 
    
         
            -
            date: 2012-03- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2012-03-05 00:00:00.000000000Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: minitest
         
     | 
| 
       16 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 16 
     | 
    
         
            +
              requirement: &17260400 !ruby/object:Gem::Requirement
         
     | 
| 
       17 
17 
     | 
    
         
             
                none: false
         
     | 
| 
       18 
18 
     | 
    
         
             
                requirements:
         
     | 
| 
       19 
19 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -21,10 +21,10 @@ dependencies: 
     | 
|
| 
       21 
21 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       22 
22 
     | 
    
         
             
              type: :development
         
     | 
| 
       23 
23 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       24 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 24 
     | 
    
         
            +
              version_requirements: *17260400
         
     | 
| 
       25 
25 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       26 
26 
     | 
    
         
             
              name: rake
         
     | 
| 
       27 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 27 
     | 
    
         
            +
              requirement: &17259880 !ruby/object:Gem::Requirement
         
     | 
| 
       28 
28 
     | 
    
         
             
                none: false
         
     | 
| 
       29 
29 
     | 
    
         
             
                requirements:
         
     | 
| 
       30 
30 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -32,10 +32,10 @@ dependencies: 
     | 
|
| 
       32 
32 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       33 
33 
     | 
    
         
             
              type: :development
         
     | 
| 
       34 
34 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       35 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 35 
     | 
    
         
            +
              version_requirements: *17259880
         
     | 
| 
       36 
36 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       37 
37 
     | 
    
         
             
              name: sqlite3-ruby
         
     | 
| 
       38 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 38 
     | 
    
         
            +
              requirement: &17259400 !ruby/object:Gem::Requirement
         
     | 
| 
       39 
39 
     | 
    
         
             
                none: false
         
     | 
| 
       40 
40 
     | 
    
         
             
                requirements:
         
     | 
| 
       41 
41 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -43,10 +43,10 @@ dependencies: 
     | 
|
| 
       43 
43 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       44 
44 
     | 
    
         
             
              type: :development
         
     | 
| 
       45 
45 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       46 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 46 
     | 
    
         
            +
              version_requirements: *17259400
         
     | 
| 
       47 
47 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       48 
48 
     | 
    
         
             
              name: pry
         
     | 
| 
       49 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 49 
     | 
    
         
            +
              requirement: &17245300 !ruby/object:Gem::Requirement
         
     | 
| 
       50 
50 
     | 
    
         
             
                none: false
         
     | 
| 
       51 
51 
     | 
    
         
             
                requirements:
         
     | 
| 
       52 
52 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -54,10 +54,10 @@ dependencies: 
     | 
|
| 
       54 
54 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       55 
55 
     | 
    
         
             
              type: :development
         
     | 
| 
       56 
56 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       57 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 57 
     | 
    
         
            +
              version_requirements: *17245300
         
     | 
| 
       58 
58 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       59 
59 
     | 
    
         
             
              name: chronic
         
     | 
| 
       60 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 60 
     | 
    
         
            +
              requirement: &17244840 !ruby/object:Gem::Requirement
         
     | 
| 
       61 
61 
     | 
    
         
             
                none: false
         
     | 
| 
       62 
62 
     | 
    
         
             
                requirements:
         
     | 
| 
       63 
63 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -65,10 +65,10 @@ dependencies: 
     | 
|
| 
       65 
65 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       66 
66 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       67 
67 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       68 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 68 
     | 
    
         
            +
              version_requirements: *17244840
         
     | 
| 
       69 
69 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       70 
70 
     | 
    
         
             
              name: activerecord
         
     | 
| 
       71 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 71 
     | 
    
         
            +
              requirement: &17244300 !ruby/object:Gem::Requirement
         
     | 
| 
       72 
72 
     | 
    
         
             
                none: false
         
     | 
| 
       73 
73 
     | 
    
         
             
                requirements:
         
     | 
| 
       74 
74 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -76,10 +76,10 @@ dependencies: 
     | 
|
| 
       76 
76 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       77 
77 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       78 
78 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       79 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 79 
     | 
    
         
            +
              version_requirements: *17244300
         
     | 
| 
       80 
80 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       81 
81 
     | 
    
         
             
              name: activesupport
         
     | 
| 
       82 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 82 
     | 
    
         
            +
              requirement: &17243780 !ruby/object:Gem::Requirement
         
     | 
| 
       83 
83 
     | 
    
         
             
                none: false
         
     | 
| 
       84 
84 
     | 
    
         
             
                requirements:
         
     | 
| 
       85 
85 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -87,18 +87,7 @@ dependencies: 
     | 
|
| 
       87 
87 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       88 
88 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       89 
89 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       90 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
       91 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       92 
     | 
    
         
            -
              name: squeel
         
     | 
| 
       93 
     | 
    
         
            -
              requirement: &19662480 !ruby/object:Gem::Requirement
         
     | 
| 
       94 
     | 
    
         
            -
                none: false
         
     | 
| 
       95 
     | 
    
         
            -
                requirements:
         
     | 
| 
       96 
     | 
    
         
            -
                - - ! '>='
         
     | 
| 
       97 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       98 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       99 
     | 
    
         
            -
              type: :runtime
         
     | 
| 
       100 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       101 
     | 
    
         
            -
              version_requirements: *19662480
         
     | 
| 
      
 90 
     | 
    
         
            +
              version_requirements: *17243780
         
     | 
| 
       102 
91 
     | 
    
         
             
            description: Seeeeeeeee Readme
         
     | 
| 
       103 
92 
     | 
    
         
             
            email:
         
     | 
| 
       104 
93 
     | 
    
         
             
            - brandonsdewitt@gmail.com
         
     | 
| 
         @@ -117,6 +106,7 @@ files: 
     | 
|
| 
       117 
106 
     | 
    
         
             
            - lib/birddog/date_expression.rb
         
     | 
| 
       118 
107 
     | 
    
         
             
            - lib/birddog/field_conditions.rb
         
     | 
| 
       119 
108 
     | 
    
         
             
            - lib/birddog/numeric_expression.rb
         
     | 
| 
      
 109 
     | 
    
         
            +
            - lib/birddog/scope_builder.rb
         
     | 
| 
       120 
110 
     | 
    
         
             
            - lib/birddog/searchable.rb
         
     | 
| 
       121 
111 
     | 
    
         
             
            - lib/birddog/version.rb
         
     | 
| 
       122 
112 
     | 
    
         
             
            - specs/birddog_spec.rb
         
     | 
| 
         @@ -139,16 +129,13 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       139 
129 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       140 
130 
     | 
    
         
             
                  segments:
         
     | 
| 
       141 
131 
     | 
    
         
             
                  - 0
         
     | 
| 
       142 
     | 
    
         
            -
                  hash:  
     | 
| 
      
 132 
     | 
    
         
            +
                  hash: 2755655051036560996
         
     | 
| 
       143 
133 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       144 
134 
     | 
    
         
             
              none: false
         
     | 
| 
       145 
135 
     | 
    
         
             
              requirements:
         
     | 
| 
       146 
     | 
    
         
            -
              - - ! ' 
     | 
| 
      
 136 
     | 
    
         
            +
              - - ! '>'
         
     | 
| 
       147 
137 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       148 
     | 
    
         
            -
                  version:  
     | 
| 
       149 
     | 
    
         
            -
                  segments:
         
     | 
| 
       150 
     | 
    
         
            -
                  - 0
         
     | 
| 
       151 
     | 
    
         
            -
                  hash: 1270257218013225858
         
     | 
| 
      
 138 
     | 
    
         
            +
                  version: 1.3.1
         
     | 
| 
       152 
139 
     | 
    
         
             
            requirements: []
         
     | 
| 
       153 
140 
     | 
    
         
             
            rubyforge_project: birddog
         
     | 
| 
       154 
141 
     | 
    
         
             
            rubygems_version: 1.8.10
         
     |