class Mobility::Backends::Sequel::KeyValue

Implements the {Mobility::Backends::KeyValue} backend for Sequel models.

@note This backend requires the cache to be enabled in order to track

and store changed translations, since Sequel does not support +build+-type
methods on associations like ActiveRecord.

Constants

Translation

Public Class Methods

build_op(attr, locale) click to toggle source

@!endgroup

# File lib/mobility/backends/sequel/key_value.rb, line 40
def build_op(attr, locale)
  QualifiedIdentifier.new(table_alias(attr, locale), value_column, locale, self, attr)
end
configure(options) click to toggle source

@!group Backend Configuration @option (see Mobility::Backends::KeyValue::ClassMethods#configure) @raise (see Mobility::Backends::KeyValue::ClassMethods#configure) @raise [CacheRequired] if cache is disabled

Calls superclass method
# File lib/mobility/backends/sequel/key_value.rb, line 28
def configure(options)
  raise CacheRequired, "Cache required for Sequel::KeyValue backend" if options[:cache] == false
  super
  if type = options[:type]
    options[:association_name] ||= :"#{options[:type]}_translations"
    options[:class_name]       ||= const_get("#{type.capitalize}Translation")
  end
rescue NameError
  raise ArgumentError, "You must define a Mobility::Sequel::#{type.capitalize}Translation class."
end
prepare_dataset(dataset, predicate, locale) click to toggle source

@param [Sequel::Dataset] dataset Dataset to prepare @param [Object] predicate Predicate @param [Symbol] locale Locale @return [Sequel::Dataset] Prepared dataset

# File lib/mobility/backends/sequel/key_value.rb, line 48
def prepare_dataset(dataset, predicate, locale)
  visit(predicate, locale).inject(dataset) do |ds, (attr, join_type)|
    join_translations(ds, attr, locale, join_type)
  end
end

Private Class Methods

join_translations(dataset, attr, locale, join_type) click to toggle source
# File lib/mobility/backends/sequel/key_value.rb, line 56
def join_translations(dataset, attr, locale, join_type)
  dataset.join_table(join_type,
                     class_name.table_name,
                     {
                       key_column => attr.to_s,
                       :locale => locale.to_s,
                       :"#{belongs_to}_type" => model_class.name,
                       :"#{belongs_to}_id" => ::Sequel[:"#{model_class.table_name}"][:id]
                     },
                     table_alias: table_alias(attr, locale))
end
visit(predicate, locale) click to toggle source

@return [Hash] Hash of attribute/join_type pairs

# File lib/mobility/backends/sequel/key_value.rb, line 69
def visit(predicate, locale)
  case predicate
  when Array
    visit_collection(predicate, locale)
  when QualifiedIdentifier
    visit_sql_identifier(predicate, locale)
  when ::Sequel::SQL::BooleanExpression
    visit_boolean(predicate, locale)
  when ::Sequel::SQL::Expression
    visit(predicate.args, locale)
  else
    {}
  end
end
visit_boolean(boolean, locale) click to toggle source
# File lib/mobility/backends/sequel/key_value.rb, line 84
def visit_boolean(boolean, locale)
  if boolean.op == :IS
    nils, ops = boolean.args.partition(&:nil?)
    if hash = visit(ops, locale)
      join_type = nils.empty? ? :inner : :left_outer
      # TODO: simplify to hash.transform_values { join_type } when
      #   support for Ruby 2.3 is deprecated
      ::Hash[hash.keys.map { |key| [key, join_type] }]
    else
      {}
    end
  elsif boolean.op == :'='
    hash = visit(boolean.args, locale)
    # TODO: simplify to hash.transform_values { :inner } when
    #   support for Ruby 2.3 is deprecated
    ::Hash[hash.keys.map { |key| [key, :inner] }]
  elsif boolean.op == :OR
    hash = boolean.args.map { |op| visit(op, locale) }.
      compact.inject(:merge)
    # TODO: simplify to hash.transform_values { :left_outer } when
    #   support for Ruby 2.3 is deprecated
    ::Hash[hash.keys.map { |key| [key, :left_outer] }]
  else
    visit(boolean.args, locale)
  end
end
visit_collection(collection, locale) click to toggle source
# File lib/mobility/backends/sequel/key_value.rb, line 111
def visit_collection(collection, locale)
  collection.map { |p| visit(p, locale) }.compact.inject do |hash, visited|
    visited.merge(hash) { |_, old, new| old == :inner ? old : new }
  end
end
visit_sql_identifier(identifier, locale) click to toggle source
# File lib/mobility/backends/sequel/key_value.rb, line 117
def visit_sql_identifier(identifier, locale)
  if identifier.backend_class == self && identifier.locale == locale
    { identifier.attribute_name => :left_outer }
  else
    {}
  end
end

Public Instance Methods

save_translations() click to toggle source

Saves translation which have been built and which have non-blank values.

# File lib/mobility/backends/sequel/key_value.rb, line 193
def save_translations
  cache.each_value do |translation|
    next unless present?(translation.__send__ value_column)
    translation.id ? translation.save : model.send("add_#{singularize(association_name)}", translation)
  end
end
translation_for(locale, **) click to toggle source

Returns translation for a given locale, or initializes one if none is present. @param [Symbol] locale @return [Mobility::Backends::Sequel::KeyValue::TextTranslation,Mobility::Backends::Sequel::KeyValue::StringTranslation]

# File lib/mobility/backends/sequel/key_value.rb, line 186
def translation_for(locale, **)
  translation = model.send(association_name).find { |t| t.__send__(key_column) == attribute && t.locale == locale.to_s }
  translation ||= class_name.new(locale: locale, key_column => attribute)
  translation
end