Module: ActiveRecordExtended::ArrayAndJsonbQueryMethods

Defined in:
lib/active_record_extended/array_and_jsonb_query_methods.rb

Instance Method Summary collapse

Instance Method Details

#any_of(*conditions) ⇒ ActiveRecord::Relation

WHERE (cond_a) OR (cond_b) OR ... -- each condition is a Hash of
attribute filters or an existing Relation. Mirrors the gem's
where.any_of(...) API so call sites stay readable.

Branches are built FROM @scope (not from @scope.klass) so any
joins/references already on the chain carry into each OR branch.
Otherwise Model.joins(:assoc).where.any_of(...) would build OR
branches without the join context and produce invalid SQL.

Returns:

  • (ActiveRecord::Relation)

    relation matching any of the given conditions



76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/active_record_extended/array_and_jsonb_query_methods.rb', line 76

def any_of(*conditions)
  return @scope if conditions.empty?

  relations = conditions.map do |cond|
    case cond
    when ActiveRecord::Relation then @scope.merge(cond)
    when Hash                   then @scope.where(cond)
    else
      raise ArgumentError, "where.any_of expects Hash or Relation; got #{cond.class}"
    end
  end

  relations.reduce { |memo, rel| memo.or(rel) }
end

#contains(opts) ⇒ ActiveRecord::Relation

column @> value -- jsonb (Hash) or array (Array) containment.
Same element-type-cast discipline as overlap for the array branch.

Parameters:

  • opts (Hash{Symbol, String => Hash, Array})

    column => value pairs

Options Hash (opts):

  • each (Hash, Array)

    key names a column, each value the contained value

Returns:

  • (ActiveRecord::Relation)

    the filtered scope

Raises:

  • (ArgumentError)

    when a value is neither Hash nor Array



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/active_record_extended/array_and_jsonb_query_methods.rb', line 49

def contains(opts)
  scope = @scope
  opts.each do |column, value|
    qualified = qualify_column(scope, column)
    scope =
      case value
      when Hash
        scope.where("#{qualified} @> ?", value.to_json)
      when Array
        cast = pg_array_cast(scope, column)
        scope.where("#{qualified} @> ARRAY[?]#{cast}", value)
      else
        raise ArgumentError, "where.contains expects Hash (jsonb) or Array; got #{value.class}"
      end
  end
  scope
end

#overlap(opts) ⇒ ActiveRecord::Relation

column && ARRAY[...] -- true when any element overlaps. Empty input
short-circuits to none (overlap with empty array is always false).

PG requires matching array element types for &&. We discover the
column's element type from AR column metadata and cast the RHS literal
accordingly — otherwise varchar[] && ARRAY['x'] (which defaults to
text[]) errors with "operator does not exist: character varying[] && text[]".

Parameters:

  • opts (Hash{Symbol, String => Object})

    column => values pairs

Options Hash (opts):

  • each (Array)

    key names a column, each value the overlapping values

Returns:

  • (ActiveRecord::Relation)

    the filtered scope



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/active_record_extended/array_and_jsonb_query_methods.rb', line 30

def overlap(opts)
  scope = @scope
  opts.each do |column, values|
    values = Array(values)
    return scope.none if values.empty?

    qualified = qualify_column(scope, column)
    cast = pg_array_cast(scope, column)
    scope = scope.where("#{qualified} && ARRAY[?]#{cast}", values)
  end
  scope
end