class Flipper::Adapters::Sequel

Attributes

name[R]

Public: The name of the adapter.

Public Class Methods

new(options = {}) click to toggle source

Public: Initialize a new Sequel adapter instance.

name - The Symbol name for this adapter. Optional (default :active_record) feature_class - The AR class responsible for the features table. gate_class - The AR class responsible for the gates table.

Allowing the overriding of name is so you can differentiate multiple instances of this adapter from each other, if, for some reason, that is a thing you do.

Allowing the overriding of the default feature/gate classes means you can roll your own tables and what not, if you so desire.

# File lib/flipper/adapters/sequel.rb, line 46
def initialize(options = {})
  @name = options.fetch(:name, :sequel)
  @feature_class = options.fetch(:feature_class) { Feature }
  @gate_class = options.fetch(:gate_class) { Gate }
end

Public Instance Methods

add(feature) click to toggle source

Public: Adds a feature to the set of known features.

# File lib/flipper/adapters/sequel.rb, line 58
def add(feature)
  # race condition, but add is only used by enable/disable which happen
  # super rarely, so it shouldn't matter in practice
  @feature_class.find_or_create(key: feature.key.to_s)
  true
end
clear(feature) click to toggle source

Public: Clears the gate values for a feature.

# File lib/flipper/adapters/sequel.rb, line 75
def clear(feature)
  @gate_class.where(feature_key: feature.key.to_s).delete
  true
end
disable(feature, gate, thing) click to toggle source

Public: Disables a gate for a given thing.

feature - The Flipper::Feature for the gate. gate - The Flipper::Gate to disable. thing - The Flipper::Type being disabled for the gate.

Returns true.

# File lib/flipper/adapters/sequel.rb, line 150
def disable(feature, gate, thing)
  case gate.data_type
  when :boolean
    clear(feature)
  when :integer
    set(feature, gate, thing)
  when :set
    @gate_class.where(gate_attrs(feature, gate, thing))
               .delete
  else
    unsupported_data_type gate.data_type
  end

  true
end
enable(feature, gate, thing) click to toggle source

Public: Enables a gate for a given thing.

feature - The Flipper::Feature for the gate. gate - The Flipper::Gate to disable. thing - The Flipper::Type being disabled for the gate.

Returns true.

# File lib/flipper/adapters/sequel.rb, line 125
def enable(feature, gate, thing)
  case gate.data_type
  when :boolean
    set(feature, gate, thing, clear: true)
  when :integer
    set(feature, gate, thing)
  when :set
    begin
      @gate_class.create(gate_attrs(feature, gate, thing))
    rescue ::Sequel::UniqueConstraintViolation
    end
  else
    unsupported_data_type gate.data_type
  end

  true
end
features() click to toggle source

Public: The set of known features.

# File lib/flipper/adapters/sequel.rb, line 53
def features
  @feature_class.all.map(&:key).to_set
end
get(feature) click to toggle source

Public: Gets the values for all gates for a given feature.

Returns a Hash of Flipper::Gate#key => value.

# File lib/flipper/adapters/sequel.rb, line 83
def get(feature)
  db_gates = @gate_class.where(feature_key: feature.key.to_s).all

  result_for_feature(feature, db_gates)
end
get_all() click to toggle source
# File lib/flipper/adapters/sequel.rb, line 99
def get_all
  feature_table = @feature_class.table_name.to_sym
  gate_table = @gate_class.table_name.to_sym
  features_sql = @feature_class.select(:key.qualify(feature_table).as(:feature_key))
      .select_append(:key.qualify(gate_table))
      .select_append(:value.qualify(gate_table))
      .left_join(@gate_class.table_name.to_sym, feature_key: :key)
      .sql

  db_gates = @gate_class.fetch(features_sql).to_a
  grouped_db_gates = db_gates.group_by(&:feature_key)
  result = Hash.new { |hash, key| hash[key] = default_config }
  features = grouped_db_gates.keys.map { |key| Flipper::Feature.new(key, self) }
  features.each do |feature|
    result[feature.key] = result_for_feature(feature, grouped_db_gates[feature.key])
  end
  result
end
get_multi(features) click to toggle source
# File lib/flipper/adapters/sequel.rb, line 89
def get_multi(features)
  db_gates = @gate_class.where(feature_key: features.map(&:key)).to_a
  grouped_db_gates = db_gates.group_by(&:feature_key)
  result = {}
  features.each do |feature|
    result[feature.key] = result_for_feature(feature, grouped_db_gates[feature.key])
  end
  result
end
remove(feature) click to toggle source

Public: Removes a feature from the set of known features.

# File lib/flipper/adapters/sequel.rb, line 66
def remove(feature)
  @feature_class.db.transaction do
    @feature_class.where(key: feature.key.to_s).delete
    clear(feature)
  end
  true
end

Private Instance Methods

gate_attrs(feature, gate, thing) click to toggle source
# File lib/flipper/adapters/sequel.rb, line 190
def gate_attrs(feature, gate, thing)
  {
    feature_key: feature.key.to_s,
    key: gate.key.to_s,
    value: thing.value.to_s,
  }
end
result_for_feature(feature, db_gates) click to toggle source
# File lib/flipper/adapters/sequel.rb, line 198
def result_for_feature(feature, db_gates)
  db_gates ||= []
  feature.gates.each_with_object({}) do |gate, result|
    result[gate.key] =
      case gate.data_type
      when :boolean
        if detected_db_gate = db_gates.detect { |db_gate| db_gate.key == gate.key.to_s }
          detected_db_gate.value
        end
      when :integer
        if detected_db_gate = db_gates.detect { |db_gate| db_gate.key == gate.key.to_s }
          detected_db_gate.value
        end
      when :set
        db_gates.select { |db_gate| db_gate.key == gate.key.to_s }.map(&:value).to_set
      else
        unsupported_data_type gate.data_type
      end
  end
end
set(feature, gate, thing, options = {}) click to toggle source
# File lib/flipper/adapters/sequel.rb, line 172
def set(feature, gate, thing, options = {})
  clear_feature = options.fetch(:clear, false)
  args = {
    feature_key: feature.key,
    key: gate.key.to_s,
  }

  @gate_class.db.transaction do
    clear(feature) if clear_feature
    @gate_class.where(args).delete

    begin
      @gate_class.create(gate_attrs(feature, gate, thing))
    rescue ::Sequel::UniqueConstraintViolation
    end
  end
end
unsupported_data_type(data_type) click to toggle source
# File lib/flipper/adapters/sequel.rb, line 168
def unsupported_data_type(data_type)
  raise "#{data_type} is not supported by this adapter"
end