Class: CafeCar::QueryBuilder
- Inherits:
-
Object
- Object
- CafeCar::QueryBuilder
- Defined in:
- lib/cafe_car/query_builder.rb
Defined Under Namespace
Classes: Op
Instance Attribute Summary collapse
-
#scope ⇒ Object
readonly
Returns the value of attribute scope.
Instance Method Summary collapse
- #arel(key) ⇒ Object
- #arel!(node) ⇒ Object
- #association!(name, value) ⇒ Object
- #association?(name) ⇒ Boolean
- #attribute!(key, value) ⇒ Object
- #attribute?(name) ⇒ Boolean
- #chomp(key) ⇒ Object
- #column(name) ⇒ Object
-
#initialize(scope) ⇒ QueryBuilder
constructor
A new instance of QueryBuilder.
- #not! ⇒ Object
- #param!(key, value) ⇒ Object
- #parse(key, value) ⇒ Object
- #parse_range(key, value) ⇒ Object
- #parse_time(value) ⇒ Object
- #parse_value(key, value) ⇒ Object
- #query ⇒ Object
- #query!(params = nil) ⇒ Object
- #reflection(name) ⇒ Object
- #scope!(name, value) ⇒ Object
- #scope?(name) ⇒ Boolean
- #search!(term) ⇒ Object
- #unscoped ⇒ Object
- #update! ⇒ Object
Constructor Details
#initialize(scope) ⇒ QueryBuilder
Returns a new instance of QueryBuilder.
29 30 31 |
# File 'lib/cafe_car/query_builder.rb', line 29 def initialize(scope) @scope = scope end |
Instance Attribute Details
#scope ⇒ Object (readonly)
Returns the value of attribute scope.
27 28 29 |
# File 'lib/cafe_car/query_builder.rb', line 27 def scope @scope end |
Instance Method Details
#arel(key) ⇒ Object
34 |
# File 'lib/cafe_car/query_builder.rb', line 34 def arel(key) = @scope.arel_table[chomp(key)] |
#arel!(node) ⇒ Object
102 |
# File 'lib/cafe_car/query_builder.rb', line 102 def arel!(node) = @scope.where!(node) |
#association!(name, value) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/cafe_car/query_builder.rb', line 133 def association!(name, value, ...) update! do case value when true then @scope.where_assoc_exists(name) when false then @scope.where_assoc_not_exists(name) when Integer, Range, /^\d+$/ @scope.where_assoc_count(parse(name, value), :==, name) when Op value = parse(name, value) @scope.where_assoc_count(value.rhs, value.flop, name) else @scope.where_assoc_exists(name) { all.query!(value, ...) } end end end |
#association?(name) ⇒ Boolean
98 |
# File 'lib/cafe_car/query_builder.rb', line 98 def association?(name) = reflection(name).present? |
#attribute!(key, value) ⇒ Object
123 124 125 126 127 128 129 130 131 |
# File 'lib/cafe_car/query_builder.rb', line 123 def attribute!(key, value) case [ key, value ] in _, Regexp @scope.where!(arel(key).matches_regexp(value.source, !value.casefold?)) in _, Op @scope.where!(parse(key, value).arel(arel(key))) else @scope.where!(key => parse(key, value)) end end |
#attribute?(name) ⇒ Boolean
99 |
# File 'lib/cafe_car/query_builder.rb', line 99 def attribute?(name) = column(name).present? |
#chomp(key) ⇒ Object
35 |
# File 'lib/cafe_car/query_builder.rb', line 35 def chomp(key) = key.to_s.sub(/\W+$/, "") |
#column(name) ⇒ Object
96 |
# File 'lib/cafe_car/query_builder.rb', line 96 def column(name) = @scope.columns_hash[name.to_s] |
#not! ⇒ Object
91 92 93 94 |
# File 'lib/cafe_car/query_builder.rb', line 91 def not!(&) inverted = unscoped.tap { _1.instance_exec(&) }.scope.invert_where update! { _1.and(inverted) } end |
#param!(key, value) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/cafe_car/query_builder.rb', line 104 def param!(key, value) case key when /^(.*?)\s*!$/ not! { param!($1, value) } when /^(.*?)\s*~$/ param!($1, Regexp.new(value, Regexp::IGNORECASE)) when /^(.*?)\s*([<>]=?)$/ param!($1, Op.new($2, value)) when method(:association?) association!(key, value) when method(:attribute?) attribute!(key, value) when method(:scope?) scope!(key, value) else raise MissingAttributeError, "can't find #{key.inspect} on #{@scope.model_name}" end end |
#parse(key, value) ⇒ Object
49 50 51 52 53 54 55 56 |
# File 'lib/cafe_car/query_builder.rb', line 49 def parse(key, value) new_value = parse_value(key, value) if new_value != value parse(key, new_value) else new_value end end |
#parse_range(key, value) ⇒ Object
43 44 45 46 47 |
# File 'lib/cafe_car/query_builder.rb', line 43 def parse_range(key, value) Range.new(parse_value(key, value.begin).then { _1.try(:begin) or _1 }, parse_value(key, value.end).then { value.exclude_end? ? _1.try(:begin) : _1.try(:end) or _1 }, value.exclude_end?) end |
#parse_time(value) ⇒ Object
37 38 39 40 41 |
# File 'lib/cafe_car/query_builder.rb', line 37 def parse_time(value) Chronic.parse(value, guess: false, context: :past) rescue NoMethodError nil end |
#parse_value(key, value) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/cafe_car/query_builder.rb', line 58 def parse_value(key, value) case value in Op(rhs: /^=(.*)$/) Op.new("#{value.op}=", $1) in Op(op: (:< | :>=), rhs: Range) value.map(&:begin) in Op(op: (:> | :<=), rhs: Range) value.map(&:end) in Range parse_range(key, value) in Array | Op value.map { parse_value(key, _1) } in "true" then true in "false" then false in String case column(key)&.type || reflection(key)&.macro when :datetime then parse_time(value) || value when :integer then value.to_i when :float then value.to_f when :belongs_to, :has_many, :has_one value.to_i else value end else value end end |
#query ⇒ Object
174 |
# File 'lib/cafe_car/query_builder.rb', line 174 def query(...) = clone.update!(&:all).query!(...) |
#query!(params = nil) ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/cafe_car/query_builder.rb', line 162 def query!(params = nil) case params when Hash then params.each { param!(_1, _2) } when Array then params.each { query! _1 } when String then search!(params) # when Arel::Nodes::Node then arel!(params) when nil else raise ArgumentError, "cannot query on #{params}" end self end |
#reflection(name) ⇒ Object
97 |
# File 'lib/cafe_car/query_builder.rb', line 97 def reflection(name) = @scope.reflect_on_association(name) |
#scope!(name, value) ⇒ Object
148 149 150 151 152 153 154 |
# File 'lib/cafe_car/query_builder.rb', line 148 def scope!(name, value) value = parse_value(name, value) arity = (@scope.scopes[name] || @scope.method(name)).arity value = nil if arity == 0 and value == true update! { _1.public_send(name, *value) } end |
#scope?(name) ⇒ Boolean
100 |
# File 'lib/cafe_car/query_builder.rb', line 100 def scope?(name) = name.intern.in? @scope.local_methods |
#search!(term) ⇒ Object
156 157 158 159 160 |
# File 'lib/cafe_car/query_builder.rb', line 156 def search!(term) @scope.search!(term) if @scope.respond_to?(:search!) @scope.query!("body~": term) if @scope < ::ActionText::RichText update! { _1.search(term) } end |
#unscoped ⇒ Object
33 |
# File 'lib/cafe_car/query_builder.rb', line 33 def unscoped = QueryBuilder.new(@scope.unscope(:where)) |
#update! ⇒ Object
85 86 87 88 89 |
# File 'lib/cafe_car/query_builder.rb', line 85 def update!(&) scope = yield @scope @scope = scope if scope self end |