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 Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(scope, store_name) ⇒ StoreChain

Returns a new instance of StoreChain.



11
12
13
14
15
16
# File 'lib/pgrel/active_record/store_chain.rb', line 11

def initialize(scope, store_name)
  @scope = scope
  @store_name = store_name
  @inverted = false
  @quoted_store_name = "#{@scope.klass.quoted_table_name}.#{@scope.klass.connection.quote_column_name(store_name)}"
end

Instance Attribute Details

#quoted_store_nameObject (readonly)

Returns the value of attribute quoted_store_name.



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

def quoted_store_name
  @quoted_store_name
end

#store_nameObject (readonly)

Returns the value of attribute store_name.



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

def store_name
  @store_name
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', ...)]


38
39
40
# File 'lib/pgrel/active_record/store_chain.rb', line 38

def contained(opts)
  update_scope "#{quoted_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', ...)]


26
27
28
# File 'lib/pgrel/active_record/store_chain.rb', line 26

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')]


51
52
53
54
55
# File 'lib/pgrel/active_record/store_chain.rb', line 51

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)


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

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