Class: ActiveRecord::QueryMethods::StoreChain

Inherits:
Object
  • Object
show all
Defined in:
lib/pgrel/active_record/store_chain.rb

Overview

Base class for different store chains (hstore, jsonb, array). Provides containment queries methods. Provides basic methods.

Direct Known Subclasses

ArrayChain, KeyStoreChain

Instance Method Summary collapse

Constructor Details

#initialize(scope, store_name) ⇒ StoreChain

Returns a new instance of StoreChain.



9
10
11
12
13
# File 'lib/pgrel/active_record/store_chain.rb', line 9

def initialize(scope, store_name)
  @scope = scope
  @store_name = store_name
  @inverted = false
end

Instance Method Details

#contained(opts) ⇒ Object

Whether the store is contained within provided store

Example

Model.create!(name: 'first', store: {b: 1})
Model.create!(name: 'second', store: {b: 1, c: 3})

data = {b: 1, c: 2}
Model.store(:store).contains(data).all #=> [Model(name: 'first', ...)]


35
36
37
# File 'lib/pgrel/active_record/store_chain.rb', line 35

def contained(opts)
  update_scope "#{@store_name} <@ #{type_cast(opts)}"
end

#contains(opts) ⇒ Object

Whether the store contains provided store

Example

Model.create!(name: 'first', store: {a: 1, b: 2})
Model.create!(name: 'second', store: {b: 1, c: 3})

data = {a: 1}
Model.store(:store).contains(data).all #=> [Model(name: 'first', ...)]


23
24
25
# File 'lib/pgrel/active_record/store_chain.rb', line 23

def contains(opts)
  update_scope contains_clause(opts)
end

#not(opts = :chain) ⇒ Object

Add negation to condition.

Example

Model.create!(name: 'first', store: {b: 2})
Model.create!(name: 'second', store: {b: 1, c: 3})

Model.store(:store).not.contains({c: 3}).all #=> [Model(name: 'first')]

Model.store(:store).not(b: 2).all #=> [Model(name: 'second')]


48
49
50
51
52
# File 'lib/pgrel/active_record/store_chain.rb', line 48

def not(opts = :chain)
  @inverted = true
  return where(opts) unless opts == :chain
  self
end

#where(*opts) ⇒ Object

Query by store values. Supports array values.

NOTE: This method uses “@>” (contains) operator with logic (AND/OR) and not uses “->” (value-by-key). The use of “contains” operator allows us to use GIN index effectively.

Example

Model.create!(name: 'first', store: {b: 1, c: 2})
Model.create!(name: 'second', store: {b: 2, c: 3})

Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
#=> (SQL) select * from ... where store @> '"c"=>"2"'::hstore

Model.store(:store, b: [1, 2]).size #=> 2
#=> (SQL) select * from ... where (store @> '"c"=>"1"'::hstore) or
                                  (store @> '"c"=>"2"'::hstore)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/pgrel/active_record/store_chain.rb', line 71

def where(*opts)
  opts.map! { |opt| opt.is_a?(Hash) ? opt : [opt] }

  update_scope(
    opts.map do |opt|
      opt.map do |k, v|
        case v
        when Array
          "(#{build_or_contains(k, v)})"
        else
          contains_clause(k => v)
        end
      end.join(' and ')
    end.join(' or ')
  )
  @scope
end