class ActiveRecord::QueryMethods::StoreChain
Base class for different store chains (hstore, jsonb, array). Provides containment queries methods. Provides basic methods.
Attributes
quoted_store_name[R]
store_name[R]
Public Class Methods
new(scope, store_name)
click to toggle source
# 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
Public Instance Methods
contained(opts)
click to toggle source
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', ...)]
# File lib/pgrel/active_record/store_chain.rb, line 38 def contained(opts) update_scope "#{quoted_store_name} <@ #{type_cast(opts)}" end
contains(opts)
click to toggle source
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', ...)]
# File lib/pgrel/active_record/store_chain.rb, line 26 def contains(opts) update_scope contains_clause(opts) end
not(opts = :chain)
click to toggle source
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')]
# 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)
click to toggle source
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)
# 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
Protected Instance Methods
invert_arel(rel)
click to toggle source
# File lib/pgrel/active_record/store_chain.rb, line 122 def invert_arel(rel) case rel when Arel::Nodes::In Arel::Nodes::NotIn.new(rel.left, rel.right) when Arel::Nodes::Equality Arel::Nodes::NotEqual.new(rel.left, rel.right) when String Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(rel)) else Arel::Nodes::Not.new(rel) end end
type_cast(value)
click to toggle source
# File lib/pgrel/active_record/store_chain.rb, line 101 def type_cast(value) ActiveRecord::Base.connection.quote( @scope.klass.type_caster.type_cast_for_database(@store_name, value) ) end
update_scope(*opts)
click to toggle source
# File lib/pgrel/active_record/store_chain.rb, line 95 def update_scope(*opts) where_clause = build_where_clause(opts) @scope.where_clause += @inverted ? where_clause.invert : where_clause @scope end
Private Instance Methods
build_or_contains(k, vals)
click to toggle source
# File lib/pgrel/active_record/store_chain.rb, line 142 def build_or_contains(k, vals) vals.map { |v| contains_clause(k => v) }.join(" or ") end
build_where_clause(opts)
click to toggle source
# File lib/pgrel/active_record/store_chain.rb, line 146 def build_where_clause(opts) if ActiveRecord.version.release >= Gem::Version.new("6.1.0") @scope.send(:build_where_clause, opts) else @scope.send(:where_clause_factory).build(opts, []) end end
contains_clause(opts)
click to toggle source
# File lib/pgrel/active_record/store_chain.rb, line 138 def contains_clause(opts) "#{quoted_store_name} @> #{type_cast(opts)}" end