Class: Mobility::Backends::Sequel::KeyValue

Inherits:
Object
  • Object
show all
Includes:
KeyValue, Mobility::Backends::Sequel, Util
Defined in:
lib/mobility/backends/sequel/key_value.rb

Overview

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.

Implements the KeyValue backend for Sequel models.

Defined Under Namespace

Modules: Cache Classes: CacheRequired, QualifiedIdentifier, StringTranslation, TextTranslation, Translatable

Constant Summary collapse

Translation =
Translatable.new(:key, :value, :translatable)

Constants included from Util

Util::VALID_CONSTANT_NAME_REGEXP

Backend Configuration collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

#blank?, #camelize, #constantize, #demodulize, #foreign_key, included, #presence, #present?, #singularize, #underscore

Methods included from KeyValue

#association_name, #class_name, #each_locale, #read, #write

Methods included from Mobility::Backends::Sequel

included

Class Method Details

.build_op(attr, locale) ⇒ Object



40
41
42
# 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) ⇒ Object

Parameters:

  • options (Hash)

    a customizable set of options

Options Hash (options):

  • type (Symbol, String)

    Column type to use

  • association_name (Symbol) — default: :<type>_translations

    Name of association method, defaults to <type>_translations

  • class_name (Symbol)

    Translation class, defaults to Mobility::<ORM>::<type>Translation

Raises:

  • (CacheRequired)

    if cache is disabled

  • (ArgumentError)

    if type is not set, and both class_name and association_name are also not set



28
29
30
31
32
33
34
35
36
37
# 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

.define_after_destroy_callback(klass) ⇒ Object

Called from setup block. Can be overridden to customize behaviour.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/mobility/backends/sequel/key_value.rb', line 96

def define_after_destroy_callback(klass)
  # Clean up *all* leftover translations of this model, only once.
  b = self
  translation_classes = [class_name, *Mobility::Backends::Sequel::KeyValue::Translation.descendants].uniq
  klass.define_method :after_destroy do
    super()

    @mobility_after_destroy_translation_classes = [] unless defined?(@mobility_after_destroy_translation_classes)
    (translation_classes - @mobility_after_destroy_translation_classes).each do |translation_class|
      translation_class.where(:"#{b.belongs_to}_id" => id, :"#{b.belongs_to}_type" => self.class.name).destroy
    end
    @mobility_after_destroy_translation_classes += translation_classes
  end
end

.define_one_to_many_association(klass, attributes) ⇒ Object

Called from setup block. Can be overridden to customize behaviour.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/mobility/backends/sequel/key_value.rb', line 55

def define_one_to_many_association(klass, attributes)
  belongs_to_id     = :"#{belongs_to}_id"
  belongs_to_type   = :"#{belongs_to}_type"

  # Track all attributes for this association, so that we can limit the scope
  # of keys for the association to only these attributes. We need to track the
  # attributes assigned to the association in case this setup code is called
  # multiple times, so we don't "forget" earlier attributes.
  #
  attrs_method_name = :"#{association_name}_attributes"
  association_attributes = (klass.instance_variable_get(:"@#{attrs_method_name}") || []) + attributes
  klass.instance_variable_set(:"@#{attrs_method_name}", association_attributes)

  klass.one_to_many association_name,
    reciprocal:      belongs_to,
    key:             belongs_to_id,
    reciprocal_type: :one_to_many,
    conditions:      { belongs_to_type => klass.to_s, key_column => association_attributes },
    adder:           proc { |translation| translation.update(belongs_to_id => pk, belongs_to_type => self.class.to_s) },
    remover:         proc { |translation| translation.update(belongs_to_id => nil, belongs_to_type => nil) },
    clearer:         proc { send_(:"#{association_name}_dataset").update(belongs_to_id => nil, belongs_to_type => nil) },
    class:           class_name
end

.define_save_callbacks(klass, attributes) ⇒ Object

Called from setup block. Can be overridden to customize behaviour.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/mobility/backends/sequel/key_value.rb', line 80

def define_save_callbacks(klass, attributes)
  b = self
  callback_methods = Module.new do
    define_method :before_save do
      super()
      send(b.association_name).select { |t| attributes.include?(t.__send__(b.key_column)) && Util.blank?(t.__send__(b.value_column)) }.each(&:destroy)
    end
    define_method :after_save do
      super()
      attributes.each { |attribute| mobility_backends[attribute].save_translations }
    end
  end
  klass.include callback_methods
end

.prepare_dataset(dataset, predicate, locale) ⇒ Sequel::Dataset

Returns Prepared dataset.

Parameters:

  • dataset (Sequel::Dataset)

    Dataset to prepare

  • predicate (Object)

    Predicate

  • locale (Symbol)

    Locale

Returns:

  • (Sequel::Dataset)

    Prepared dataset



48
49
50
51
52
# 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

Instance Method Details

#save_translationsObject

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



202
203
204
205
206
207
# File 'lib/mobility/backends/sequel/key_value.rb', line 202

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) ⇒ Mobility::Backends::Sequel::KeyValue::TextTranslation, Mobility::Backends::Sequel::KeyValue::StringTranslation

Returns translation for a given locale, or initializes one if none is present.



195
196
197
198
199
# File 'lib/mobility/backends/sequel/key_value.rb', line 195

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