module Moneta::Adapters::Sequel::PostgresHStore

@api private

Public Class Methods

extended(mod) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 8
def self.extended(mod)
  mod.backend.extension :pg_hstore
  mod.backend.extension :pg_array
end

Public Instance Methods

clear(options = {}) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 68
def clear(options = {})
  @clear.call(row: config.hstore)
  self
end
create(key, value, options = {}) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 53
def create(key, value, options = {})
  @backend.transaction do
    create_row
    1 ==
      if @create
        @create.call(row: config.hstore, key: key, pair: ::Sequel.hstore(key => value))
      else
        @table
          .where(config.key_column => config.hstore)
          .exclude(::Sequel[config.value_column].hstore.key?(key))
          .update(config.value_column => ::Sequel[config.value_column].hstore.merge(key => value))
      end
  end
end
delete(key, options = {}) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 36
def delete(key, options = {})
  @backend.transaction do
    value = load(key, options)
    @delete.call(row: config.hstore, key: key)
    value
  end
end
each_key() { |row| ... } click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 100
def each_key
  return enum_for(:each_key) { @size.call(row: config.hstore)[:size] } unless block_given?

  ds =
    if config.each_key_server
      @table.server(config.each_key_server)
    else
      @table
    end
  ds = ds.order(:skeys) unless @table.respond_to?(:use_cursor)
  ds.where(config.key_column => config.hstore)
    .select(::Sequel[config.value_column].hstore.skeys)
    .paged_each do |row|
      yield row[:skeys]
    end
  self
end
increment(key, amount = 1, options = {}) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 44
def increment(key, amount = 1, options = {})
  @backend.transaction do
    create_row
    if row = @increment.call(row: config.hstore, key: key, amount: amount).first
      row[:value].to_i
    end
  end
end
key?(key, options = {}) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 13
def key?(key, options = {})
  if @key
    row = @key.call(row: config.hstore, key: key) || false
    row && row[:present]
  else
    @key_pl.get(key)
  end
end
load(key, options = {}) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 30
def load(key, options = {})
  if row = @load.call(row: config.hstore, key: key)
    row[:value]
  end
end
merge!(pairs, options = {}, &block) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 89
def merge!(pairs, options = {}, &block)
  @backend.transaction do
    create_row
    pairs = yield_merge_pairs(pairs, &block) if block_given?
    hash = Hash === pairs ? pairs : Hash[pairs.to_a]
    @store.call(row: config.hstore, pair: ::Sequel.hstore(hash))
  end

  self
end
slice(*keys, **options) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 81
def slice(*keys, **options)
  if row = @slice.call(row: config.hstore, keys: ::Sequel.pg_array(keys))
    row[:pairs].to_h
  else
    []
  end
end
store(key, value, options = {}) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 22
def store(key, value, options = {})
  @backend.transaction do
    create_row
    @store.call(row: config.hstore, pair: ::Sequel.hstore(key => value))
  end
  value
end
values_at(*keys, **options) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 73
def values_at(*keys, **options)
  if row = @values_at.call(row: config.hstore, keys: ::Sequel.pg_array(keys))
    row[:values].to_a
  else
    []
  end
end

Protected Instance Methods

create_row() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 120
def create_row
  @create_row.call(row: config.hstore)
end
create_table() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 124
def create_table
  key_column = config.key_column
  value_column = config.value_column

  @backend.create_table?(config.table) do
    column key_column, String, null: false, primary_key: true
    column value_column, :hstore
    index value_column, type: :gin
  end
end
prepare_clear() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 158
def prepare_clear
  @clear = @table.where(config.key_column => :$row).prepare(:update, statement_id(:hstore_clear), config.value_column => '')
end
prepare_create() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 204
def prepare_create
  # Under JRuby we can't use a prepared statement for queries involving
  # the hstore `?` (key?) operator.  See
  # https://stackoverflow.com/questions/11940401/escaping-hstore-contains-operators-in-a-jdbc-prepared-statement
  return if defined?(JRUBY_VERSION)
  @create = @table
    .where(config.key_column => :$row)
    .exclude(::Sequel[config.value_column].hstore.key?(:$key))
    .prepare(:update, statement_id(:hstore_create), config.value_column => ::Sequel[config.value_column].hstore.merge(:$pair))
end
prepare_create_row() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 152
def prepare_create_row
  @create_row = @table
    .insert_ignore
    .prepare(:insert, statement_id(:hstore_create_row), config.key_column => :$row, config.value_column => '')
end
prepare_delete() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 199
def prepare_delete
  @delete = @table.where(config.key_column => :$row)
    .prepare(:update, statement_id(:hstore_delete), config.value_column => ::Sequel[config.value_column].hstore.delete(:$key))
end
prepare_increment() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 180
def prepare_increment
  pair = ::Sequel[:hstore]
    .function(:$key, (
      ::Sequel[:coalesce].function(::Sequel[config.value_column].hstore[:$key].cast(Integer), 0) +
      :$amount
    ).cast(String))

  @increment = @table
    .returning(::Sequel[config.value_column].hstore[:$key].as(:value))
    .where(config.key_column => :$row)
    .prepare(:update, statement_id(:hstore_increment), config.value_column => ::Sequel.join([config.value_column, pair]))
end
prepare_key() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 162
def prepare_key
  if defined?(JRUBY_VERSION)
    @key_pl = ::Sequel::Dataset::PlaceholderLiteralizer.loader(@table) do |pl, ds|
      ds.where(config.key_column => config.hstore).select(::Sequel[config.value_column].hstore.key?(pl.arg))
    end
  else
    @key = @table.where(config.key_column => :$row)
      .select(::Sequel[config.value_column].hstore.key?(:$key).as(:present))
      .prepare(:first, statement_id(:hstore_key))
  end
end
prepare_load() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 193
def prepare_load
  @load = @table.where(config.key_column => :$row)
    .select(::Sequel[config.value_column].hstore[:$key].as(:value))
    .prepare(:first, statement_id(:hstore_load))
end
prepare_size() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 237
def prepare_size
  @size = @backend
    .from(@table.where(config.key_column => :$row)
    .select(::Sequel[config.value_column].hstore.each))
    .select { count.function.*.as(:size) }
    .prepare(:first, statement_id(:hstore_size))
end
prepare_slice() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 229
def prepare_slice
  slice = @table
    .where(config.key_column => :$row)
    .select(::Sequel[config.value_column].hstore.slice(:$keys).as(:pairs))
  @slice = slice.prepare(:first, statement_id(:hstore_slice))
  @slice_for_update = slice.for_update.prepare(:first, statement_id(:hstore_slice_for_update))
end
prepare_statements() click to toggle source
Calls superclass method
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 144
def prepare_statements
  super
  prepare_create_row
  prepare_clear
  prepare_values_at
  prepare_size
end
prepare_store() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 174
def prepare_store
  @store = @table
    .where(config.key_column => :$row)
    .prepare(:update, statement_id(:hstore_store), config.value_column => ::Sequel[config.value_column].hstore.merge(:$pair))
end
prepare_values_at() click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 215
def prepare_values_at
  # Sequel's hstore_ops gets confused if we try to construct this
  # directly, because the CAST is not an array literal, or a PG array
  lookup = ::Sequel::SQL::PlaceholderLiteralString.new(
    ['(', '->', ')'],
    [config.value_column, ::Sequel.cast(:$keys, :"text[]")]
  )

  @values_at = @table
    .where(config.key_column => :$row)
    .select(lookup.as(:values))
    .prepare(:first, statement_id(:hstore_values_at))
end
slice_for_update(pairs) click to toggle source
# File lib/moneta/adapters/sequel/postgres_hstore.rb, line 135
def slice_for_update(pairs)
  keys = pairs.map { |k, _| k }.to_a
  if row = @slice_for_update.call(row: config.hstore, keys: ::Sequel.pg_array(keys))
    row[:pairs].to_h
  else
    {}
  end
end