Class: OrderQuery::WhereBuilder
- Inherits:
-
Object
- Object
- OrderQuery::WhereBuilder
- Defined in:
- lib/order_query/where_builder.rb
Overview
Build where clause for searching around a record in an order space
Constant Summary collapse
- EMPTY_FILTER =
[''.freeze, []]
Class Attribute Summary collapse
-
.wrap_top_level_or ⇒ Object
Returns the value of attribute wrap_top_level_or.
Instance Attribute Summary collapse
- #order ⇒ OrderQuery::OrderSpace readonly
- #record ⇒ ActiveRecord::Base readonly
Instance Method Summary collapse
- #attr_value(cond) ⇒ Object
-
#build_query(mode) ⇒ query, parameters
Conditions that exclude all elements not before / after the current one.
-
#group_operators(term_pairs) ⇒ query, parameters
Join conditions with operators and parenthesis Since x matches order criteria with values that come before / after the current record, and y matches order criteria with values equal to the current record’s value (for resolving ties), the resulting condition matches just the elements that come before / after the record.
-
#initialize(record, order_space) ⇒ WhereBuilder
constructor
A new instance of WhereBuilder.
-
#join_terms(op, *terms) ⇒ query, parameters
joins terms with an operator.
-
#where_eq(cond) ⇒ query, params
Unless order attribute is unique, such as id, return [‘WHERE value = ?’, current value].
- #where_in(cond, values) ⇒ Object
-
#where_mode(cond, mode, strict = true) ⇒ query, params
Return query conditions for attribute values before / after the current one.
- #where_ray(cond, from, mode, strict = true) ⇒ Object
Constructor Details
#initialize(record, order_space) ⇒ WhereBuilder
Returns a new instance of WhereBuilder.
11 12 13 14 |
# File 'lib/order_query/where_builder.rb', line 11 def initialize(record, order_space) @order = order_space @record = record end |
Class Attribute Details
.wrap_top_level_or ⇒ Object
Returns the value of attribute wrap_top_level_or.
112 113 114 |
# File 'lib/order_query/where_builder.rb', line 112 def wrap_top_level_or @wrap_top_level_or end |
Instance Attribute Details
#order ⇒ OrderQuery::OrderSpace (readonly)
7 8 9 |
# File 'lib/order_query/where_builder.rb', line 7 def order @order end |
#record ⇒ ActiveRecord::Base (readonly)
5 6 7 |
# File 'lib/order_query/where_builder.rb', line 5 def record @record end |
Instance Method Details
#attr_value(cond) ⇒ Object
107 108 109 |
# File 'lib/order_query/where_builder.rb', line 107 def attr_value(cond) record.send cond.name end |
#build_query(mode) ⇒ query, parameters
Returns conditions that exclude all elements not before / after the current one.
18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/order_query/where_builder.rb', line 18 def build_query(mode) conditions = order.conditions terms = conditions.map { |cond| [where_mode(cond, mode, true), where_eq(cond)] } query = group_operators terms # Wrap top level OR clause for performance, see https://github.com/glebm/order_query/issues/3 if self.class.wrap_top_level_or && !terms[0].include?(EMPTY_FILTER) join_terms 'AND'.freeze, where_mode(conditions.first, mode, false), ["(#{query[0]})", query[1]] else query end end |
#group_operators(term_pairs) ⇒ query, parameters
Join conditions with operators and parenthesis Since x matches order criteria with values that come before / after the current record, and y matches order criteria with values equal to the current record’s value (for resolving ties), the resulting condition matches just the elements that come before / after the record
44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/order_query/where_builder.rb', line 44 def group_operators(term_pairs) # create "x OR y" string disjunctive = join_terms 'OR'.freeze, *term_pairs[0] rest = term_pairs.from(1) if rest.present? # nest the remaining pairs recursively, appending them with " AND " rest_grouped = group_operators rest rest_grouped[0] = "(#{rest_grouped[0]})" unless rest.length == 1 join_terms 'AND'.freeze, disjunctive, rest_grouped else disjunctive end end |
#join_terms(op, *terms) ⇒ query, parameters
joins terms with an operator
60 61 62 63 |
# File 'lib/order_query/where_builder.rb', line 60 def join_terms(op, *terms) [terms.map { |t| t.first.presence }.compact.join(" #{op} "), terms.map(&:second).reduce(:+) || []] end |
#where_eq(cond) ⇒ query, params
Returns Unless order attribute is unique, such as id, return [‘WHERE value = ?’, current value].
68 69 70 71 72 73 74 |
# File 'lib/order_query/where_builder.rb', line 68 def where_eq(cond) if cond.unique? EMPTY_FILTER else [%Q(#{cond.col_name_sql} = ?).freeze, [attr_value(cond)]] end end |
#where_in(cond, values) ⇒ Object
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/order_query/where_builder.rb', line 83 def where_in(cond, values) case values.length when 0 EMPTY_FILTER when 1 ["#{cond.col_name_sql} = ?".freeze, [values]] else ["#{cond.col_name_sql} IN (?)".freeze, [values]] end end |
#where_mode(cond, mode, strict = true) ⇒ query, params
Return query conditions for attribute values before / after the current one
96 97 98 99 100 101 102 103 104 105 |
# File 'lib/order_query/where_builder.rb', line 96 def where_mode(cond, mode, strict = true) value = attr_value cond if cond.ray? where_ray cond, value, mode, strict else # ord is an array of sort values, ordered first to last # if current not in result set, do not apply filter where_in cond, cond.values_around(value, mode, strict) end end |
#where_ray(cond, from, mode, strict = true) ⇒ Object
76 77 78 79 80 81 |
# File 'lib/order_query/where_builder.rb', line 76 def where_ray(cond, from, mode, strict = true) ops = %w(< >) ops = ops.reverse if mode == :after op = {asc: ops[0], desc: ops[1]}[cond.order || :asc] ["#{cond.col_name_sql} #{op}#{'=' unless strict} ?".freeze, [from]] end |