Class: Moneta::Adapters::Sequel

Inherits:
Object
  • Object
show all
Includes:
Defaults
Defined in:
lib/moneta/adapters/sequel.rb

Overview

Sequel backend

Direct Known Subclasses

MySQL, Postgres, PostgresHStore, SQLite

Defined Under Namespace

Classes: MySQL, Postgres, PostgresHStore, SQLite

Constant Summary collapse

UniqueConstraintViolation =

Sequel::UniqueConstraintViolation is defined since sequel 3.44.0 older versions raise a Sequel::DatabaseError.

defined?(::Sequel::UniqueConstraintViolation) ? ::Sequel::UniqueConstraintViolation : ::Sequel::DatabaseError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Defaults

#[], #[]=, #decrement, #each_key, #features, #fetch, #fetch_values, included, #merge!, #slice, #supports?, #values_at

Methods included from OptionSupport

#expires, #prefix, #raw, #with

Constructor Details

#initialize(options, backend) ⇒ Sequel

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Sequel


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/moneta/adapters/sequel.rb', line 81

def initialize(options, backend)
  @backend = backend
  @table_name = (options.delete(:table) || :moneta).to_sym
  @key_column = options.delete(:key_column) || :k
  @value_column = options.delete(:value_column) || :v

  create_proc = options.delete(:create_table)
  if create_proc.nil?
    create_table
  elsif create_proc
    create_proc.call(@backend)
  end

  @table = @backend[@table_name]
end

Instance Attribute Details

#backendObject (readonly)


15
16
17
# File 'lib/moneta/adapters/sequel.rb', line 15

def backend
  @backend
end

#key_columnObject (readonly)


15
16
17
# File 'lib/moneta/adapters/sequel.rb', line 15

def key_column
  @key_column
end

#value_columnObject (readonly)


15
16
17
# File 'lib/moneta/adapters/sequel.rb', line 15

def value_column
  @value_column
end

Class Method Details

.new(options = {}) ⇒ Object

Options Hash (options):

  • :db (String)

    Sequel database

  • :table (String, Symbol) — default: :moneta

    Table name

  • :extensions (Array) — default: []

    List of Sequel extensions

  • :connection_validation_timeout (Integer) — default: nil

    Sequel connection_validation_timeout

  • :backend (Sequel::Database)

    Use existing backend instance

  • :optimize (Boolean) — default: true

    Set to false to prevent database-specific optimisations

  • :create_table (Proc, Boolean)

    Provide a Proc for creating the table, or set to false to disable table creation all together. If a Proc is given, it will be called regardless of whether the table exists already.

  • :key_column (Symbol) — default: :k

    The name of the key column

  • :value_column (Symbol) — default: :v

    The name of the value column

  • :hstore (String)

    If using Postgres, keys and values are stored in a single row of the table in the value_column using the hstore format. The row to use is the one where the value_column is equal to the value of this option, and will be created if it doesn't exist.

  • All (Object)

    other options passed to `Sequel#connect`


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/moneta/adapters/sequel.rb', line 35

def self.new(*args)
  # Calls to subclass.new (below) are differentiated by # of args
  return super if args.length == 2
  options = args.first || {}

  extensions = options.delete(:extensions)
  connection_validation_timeout = options.delete(:connection_validation_timeout)
  optimize = options.delete(:optimize)
  backend = options.delete(:backend) ||
    begin
      raise ArgumentError, 'Option :db is required' unless db = options.delete(:db)
      other_cols = [:table, :create_table, :key_column, :value_column, :hstore]
      ::Sequel.connect(db, options.reject { |k,_| other_cols.member?(k) }).tap do |backend|
        if extensions
          raise ArgumentError, 'Option :extensions must be an Array' unless extensions.is_a?(Array)
          extensions.map(&:to_sym).each(&backend.method(:extension))
        end

        if connection_validation_timeout
          backend.pool.connection_validation_timeout = connection_validation_timeout
        end
      end
    end

  instance =
    if optimize.nil? || optimize
      case backend.database_type
      when :mysql
        MySQL.new(options, backend)
      when :postgres
        if options[:hstore]
          PostgresHStore.new(options, backend)
        elsif matches = backend.get(::Sequel[:version].function).match(/PostgreSQL (\d+)\.(\d+)/)
          # Our optimisations only work on Postgres 9.5+
          major, minor = matches[1..2].map(&:to_i)
          Postgres.new(options, backend) if major > 9 || (major == 9 && minor >= 5)
        end
      when :sqlite
        SQLite.new(options, backend)
      end
    end

  instance || super(options, backend)
end

Instance Method Details

#clear(options = {}) ⇒ void

This method returns an undefined value.

Clear all keys in this store


155
156
157
158
# File 'lib/moneta/adapters/sequel.rb', line 155

def clear(options = {})
  @table.delete
  self
end

#closeObject

Explicitly close the store


161
162
163
164
# File 'lib/moneta/adapters/sequel.rb', line 161

def close
  @backend.disconnect
  nil
end

#create(key, value, options = {}) ⇒ Object

Store value with key

Options Hash (options):

  • :expires (Integer)

    Set expiration time (See Expires)

  • :raw (Boolean)

    Raw access without value transformation (See Transformer)

  • :prefix (String)

    Prefix key (See Transformer)

  • Other (Object)

    options as defined by the adapters or middleware


120
121
122
123
124
125
# File 'lib/moneta/adapters/sequel.rb', line 120

def create(key, value, options = {})
  @table.insert(key_column => key, value_column => blob(value))
  true
rescue UniqueConstraintViolation
  false
end

#delete(key, options = {}) ⇒ Object

Delete the key from the store and return the current value

Options Hash (options):

  • :raw (Boolean)

    Raw access without value transformation (See Transformer)

  • :prefix (String)

    Prefix key (See Transformer)

  • Other (Object)

    options as defined by the adapters or middleware


148
149
150
151
152
# File 'lib/moneta/adapters/sequel.rb', line 148

def delete(key, options = {})
  value = load(key, options)
  @table.filter(key_column => key).delete
  value
end

#increment(key, amount = 1, options = {}) ⇒ Object

Note:

Not every Moneta store implements this method, a NotImplementedError is raised if it is not supported.

Atomically increment integer value with key

This method also accepts negative amounts.

Options Hash (options):

  • :prefix (String)

    Prefix key (See Transformer)

  • Other (Object)

    options as defined by the adapters or middleware


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/moneta/adapters/sequel.rb', line 128

def increment(key, amount = 1, options = {})
  @backend.transaction do
    if existing = @table.where(key_column => key).for_update.get(value_column)
      total = amount + Integer(existing)
      raise "no update" unless @table.
        where(key_column => key).
        update(value_column => blob(total.to_s)) == 1
      total
    else
      @table.insert(key_column => key, value_column => blob(amount.to_s))
      amount
    end
  end
rescue ::Sequel::DatabaseError
  # Concurrent modification might throw a bunch of different errors
  tries ||= 0
  (tries += 1) < 10 ? retry : raise
end

#key?(key, options = {}) ⇒ Boolean

Exists the value with key

Options Hash (options):

  • :expires (Integer)

    Update expiration time (See Expires)

  • :prefix (String)

    Prefix key (See Transformer)

  • Other (Object)

    options as defined by the adapters or middleware


98
99
100
# File 'lib/moneta/adapters/sequel.rb', line 98

def key?(key, options = {})
  !@table.where(key_column => key).empty?
end

#load(key, options = {}) ⇒ Object

Fetch value with key. Return nil if the key doesn't exist

Options Hash (options):

  • :expires (Integer)

    Update expiration time (See Expires)

  • :raw (Boolean)

    Raw access without value transformation (See Transformer)

  • :prefix (String)

    Prefix key (See Transformer)

  • :sync (Boolean)

    Synchronized load (Cache reloads from adapter, Daybreak syncs with file)

  • Other (Object)

    options as defined by the adapters or middleware


103
104
105
# File 'lib/moneta/adapters/sequel.rb', line 103

def load(key, options = {})
  @table.where(key_column => key).get(value_column)
end

#store(key, value, options = {}) ⇒ Object

Store value with key

Options Hash (options):

  • :expires (Integer)

    Set expiration time (See Expires)

  • :raw (Boolean)

    Raw access without value transformation (See Transformer)

  • :prefix (String)

    Prefix key (See Transformer)

  • Other (Object)

    options as defined by the adapters or middleware


108
109
110
111
112
113
114
115
116
117
# File 'lib/moneta/adapters/sequel.rb', line 108

def store(key, value, options = {})
  blob_value = blob(value)
  unless @table.where(key_column => key).update(value_column => blob(value)) == 1
    @table.insert(key_column => key, value_column => blob(value))
  end
  value
rescue ::Sequel::DatabaseError
  tries ||= 0
  (tries += 1) < 10 ? retry : raise
end