mobility 1.0.0.alpha → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +54 -1
  5. data/Gemfile +5 -16
  6. data/Gemfile.lock +30 -82
  7. data/README.md +24 -29
  8. data/lib/mobility.rb +67 -9
  9. data/lib/mobility/backend.rb +8 -10
  10. data/lib/mobility/backends.rb +1 -1
  11. data/lib/mobility/backends/active_record.rb +1 -1
  12. data/lib/mobility/backends/active_record/column.rb +1 -1
  13. data/lib/mobility/backends/active_record/container.rb +6 -9
  14. data/lib/mobility/backends/active_record/hstore.rb +4 -4
  15. data/lib/mobility/backends/active_record/json.rb +3 -3
  16. data/lib/mobility/backends/active_record/jsonb.rb +3 -3
  17. data/lib/mobility/backends/active_record/key_value.rb +27 -11
  18. data/lib/mobility/backends/active_record/serialized.rb +4 -0
  19. data/lib/mobility/backends/active_record/table.rb +12 -7
  20. data/lib/mobility/backends/container.rb +10 -2
  21. data/lib/mobility/backends/hash_valued.rb +4 -0
  22. data/lib/mobility/backends/jsonb.rb +1 -1
  23. data/lib/mobility/backends/key_value.rb +12 -15
  24. data/lib/mobility/backends/sequel.rb +34 -2
  25. data/lib/mobility/backends/sequel/container.rb +8 -8
  26. data/lib/mobility/backends/sequel/hstore.rb +1 -1
  27. data/lib/mobility/backends/sequel/json.rb +1 -0
  28. data/lib/mobility/backends/sequel/key_value.rb +79 -12
  29. data/lib/mobility/backends/sequel/pg_hash.rb +6 -6
  30. data/lib/mobility/backends/sequel/serialized.rb +4 -0
  31. data/lib/mobility/backends/sequel/table.rb +18 -8
  32. data/lib/mobility/backends/table.rb +29 -29
  33. data/lib/mobility/pluggable.rb +21 -1
  34. data/lib/mobility/plugin.rb +2 -2
  35. data/lib/mobility/plugins.rb +2 -0
  36. data/lib/mobility/plugins/active_model/dirty.rb +11 -5
  37. data/lib/mobility/plugins/active_record.rb +3 -0
  38. data/lib/mobility/plugins/active_record/backend.rb +2 -0
  39. data/lib/mobility/plugins/active_record/query.rb +7 -7
  40. data/lib/mobility/plugins/active_record/uniqueness_validation.rb +5 -1
  41. data/lib/mobility/plugins/arel.rb +125 -0
  42. data/lib/mobility/plugins/arel/nodes.rb +15 -0
  43. data/lib/mobility/plugins/arel/nodes/pg_ops.rb +134 -0
  44. data/lib/mobility/plugins/attribute_methods.rb +1 -0
  45. data/lib/mobility/plugins/attributes.rb +17 -15
  46. data/lib/mobility/plugins/backend.rb +45 -22
  47. data/lib/mobility/plugins/cache.rb +12 -5
  48. data/lib/mobility/plugins/default.rb +1 -1
  49. data/lib/mobility/plugins/fallbacks.rb +4 -4
  50. data/lib/mobility/plugins/fallthrough_accessors.rb +5 -6
  51. data/lib/mobility/plugins/locale_accessors.rb +2 -5
  52. data/lib/mobility/plugins/presence.rb +1 -1
  53. data/lib/mobility/plugins/reader.rb +2 -2
  54. data/lib/mobility/plugins/sequel/dirty.rb +2 -2
  55. data/lib/mobility/plugins/writer.rb +1 -1
  56. data/lib/mobility/version.rb +2 -2
  57. data/lib/rails/generators/mobility/templates/create_string_translations.rb +0 -1
  58. data/lib/rails/generators/mobility/templates/create_text_translations.rb +0 -1
  59. data/lib/rails/generators/mobility/templates/initializer.rb +11 -3
  60. metadata +14 -20
  61. metadata.gz.sig +0 -0
  62. data/lib/mobility/active_record/model_translation.rb +0 -14
  63. data/lib/mobility/active_record/string_translation.rb +0 -10
  64. data/lib/mobility/active_record/text_translation.rb +0 -10
  65. data/lib/mobility/active_record/translation.rb +0 -14
  66. data/lib/mobility/arel.rb +0 -49
  67. data/lib/mobility/arel/nodes.rb +0 -13
  68. data/lib/mobility/arel/nodes/pg_ops.rb +0 -132
  69. data/lib/mobility/arel/visitor.rb +0 -61
  70. data/lib/mobility/sequel/column_changes.rb +0 -28
  71. data/lib/mobility/sequel/hash_initializer.rb +0 -21
  72. data/lib/mobility/sequel/model_translation.rb +0 -20
  73. data/lib/mobility/sequel/sql.rb +0 -16
  74. data/lib/mobility/sequel/string_translation.rb +0 -10
  75. data/lib/mobility/sequel/text_translation.rb +0 -10
  76. data/lib/mobility/sequel/translation.rb +0 -53
metadata.gz.sig CHANGED
Binary file
@@ -1,14 +0,0 @@
1
- module Mobility
2
- module ActiveRecord
3
- =begin
4
-
5
- Subclassed dynamically to generate translation class in
6
- {Backends::ActiveRecord::Table} backend.
7
-
8
- =end
9
- class ModelTranslation < ::ActiveRecord::Base
10
- self.abstract_class = true
11
- validates :locale, presence: true
12
- end
13
- end
14
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/active_record/translation"
3
-
4
- module Mobility
5
- module ActiveRecord
6
- class StringTranslation < Translation
7
- self.table_name = "mobility_string_translations"
8
- end
9
- end
10
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/active_record/translation"
3
-
4
- module Mobility
5
- module ActiveRecord
6
- class TextTranslation < Translation
7
- self.table_name = "mobility_text_translations"
8
- end
9
- end
10
- end
@@ -1,14 +0,0 @@
1
- module Mobility
2
- module ActiveRecord
3
- # @abstract Subclass and set +table_name+ to implement for a particular column type.
4
- class Translation < ::ActiveRecord::Base
5
- self.abstract_class = true
6
-
7
- belongs_to :translatable, polymorphic: true, touch: true
8
-
9
- validates :key, presence: true, uniqueness: { scope: [:translatable_id, :translatable_type, :locale], case_sensitive: true }
10
- validates :translatable, presence: true
11
- validates :locale, presence: true
12
- end
13
- end
14
- end
@@ -1,49 +0,0 @@
1
- # frozen-string-literal: true
2
- require "mobility/arel/nodes"
3
- require "mobility/arel/visitor"
4
-
5
- module Mobility
6
- module Arel
7
- module MobilityExpressions
8
- include ::Arel::Expressions
9
-
10
- # @note This is necessary in order to ensure that when a translated
11
- # attribute is selected with an alias using +AS+, the resulting
12
- # expression can still be counted without blowing up.
13
- #
14
- # Extending +::Arel::Expressions+ is necessary to convince ActiveRecord
15
- # that this node should not be stringified, which otherwise would
16
- # result in garbage SQL.
17
- #
18
- # @see https://github.com/rails/rails/blob/847342c25c61acaea988430dc3ab66a82e3ed486/activerecord/lib/active_record/relation/calculations.rb#L261
19
- def as(*)
20
- super
21
- .extend(::Arel::Expressions)
22
- .extend(Countable)
23
- end
24
-
25
- module Countable
26
- # @note This allows expressions with selected translated attributes to
27
- # be counted.
28
- def count(*args)
29
- left.count(*args)
30
- end
31
- end
32
- end
33
-
34
- class Attribute < ::Arel::Attributes::Attribute
35
- include MobilityExpressions
36
-
37
- attr_reader :backend_class
38
- attr_reader :locale
39
- attr_reader :attribute_name
40
-
41
- def initialize(relation, column_name, locale, backend_class, attribute_name: nil)
42
- @backend_class = backend_class
43
- @locale = locale
44
- @attribute_name = attribute_name || column_name
45
- super(relation, column_name)
46
- end
47
- end
48
- end
49
- end
@@ -1,13 +0,0 @@
1
- # frozen-string-literal: true
2
- module Mobility
3
- module Arel
4
- module Nodes
5
- class Binary < ::Arel::Nodes::Binary; end
6
- class Grouping < ::Arel::Nodes::Grouping; end
7
-
8
- ::Arel::Visitors::ToSql.class_eval do
9
- alias :visit_Mobility_Arel_Nodes_Grouping :visit_Arel_Nodes_Grouping
10
- end
11
- end
12
- end
13
- end
@@ -1,132 +0,0 @@
1
- # frozen-string-literal: true
2
- require "mobility/arel"
3
-
4
- module Mobility
5
- module Arel
6
- module Nodes
7
- %w[
8
- JsonDashArrow
9
- JsonDashDoubleArrow
10
- JsonbDashArrow
11
- JsonbDashDoubleArrow
12
- JsonbQuestion
13
- HstoreDashArrow
14
- HstoreQuestion
15
- ].each do |name|
16
- const_set name, (Class.new(Binary) do
17
- include ::Arel::Predications
18
- include ::Arel::OrderPredications
19
- include ::Arel::AliasPredication
20
- include ::Mobility::Arel::MobilityExpressions
21
-
22
- def lower
23
- super self
24
- end
25
- end)
26
- end
27
-
28
- # Needed for AR 4.2, can be removed when support is deprecated
29
- if ::ActiveRecord::VERSION::STRING < '5.0'
30
- [JsonbDashDoubleArrow, HstoreDashArrow].each do |klass|
31
- klass.class_eval do
32
- def quoted_node other
33
- other && super
34
- end
35
- end
36
- end
37
- end
38
-
39
- class Jsonb < JsonbDashDoubleArrow
40
- def to_dash_arrow
41
- JsonbDashArrow.new left, right
42
- end
43
-
44
- def to_question
45
- JsonbQuestion.new left, right
46
- end
47
-
48
- def eq other
49
- case other
50
- when NilClass
51
- to_question.not
52
- when Integer, Array, ::Hash
53
- to_dash_arrow.eq other.to_json
54
- when Jsonb
55
- to_dash_arrow.eq other.to_dash_arrow
56
- when JsonbDashArrow
57
- to_dash_arrow.eq other
58
- else
59
- super
60
- end
61
- end
62
- end
63
-
64
- class Hstore < HstoreDashArrow
65
- def to_question
66
- HstoreQuestion.new left, right
67
- end
68
-
69
- def eq other
70
- other.nil? ? to_question.not : super
71
- end
72
- end
73
-
74
- class Json < JsonDashDoubleArrow; end
75
-
76
- class JsonContainer < Json
77
- def initialize column, locale, attr
78
- super(Arel::Nodes::JsonDashArrow.new(column, locale), attr)
79
- end
80
- end
81
-
82
- class JsonbContainer < Jsonb
83
- def initialize column, locale, attr
84
- @column, @locale = column, locale
85
- super(JsonbDashArrow.new(column, locale), attr)
86
- end
87
-
88
- def eq other
89
- other.nil? ? super.or(JsonbQuestion.new(@column, @locale).not) : super
90
- end
91
- end
92
- end
93
-
94
- module Visitors
95
- def visit_Mobility_Arel_Nodes_JsonDashArrow o, a
96
- json_infix o, a, '->'
97
- end
98
-
99
- def visit_Mobility_Arel_Nodes_JsonDashDoubleArrow o, a
100
- json_infix o, a, '->>'
101
- end
102
-
103
- def visit_Mobility_Arel_Nodes_JsonbDashArrow o, a
104
- json_infix o, a, '->'
105
- end
106
-
107
- def visit_Mobility_Arel_Nodes_JsonbDashDoubleArrow o, a
108
- json_infix o, a, '->>'
109
- end
110
-
111
- def visit_Mobility_Arel_Nodes_JsonbQuestion o, a
112
- json_infix o, a, '?'
113
- end
114
-
115
- def visit_Mobility_Arel_Nodes_HstoreDashArrow o, a
116
- json_infix o, a, '->'
117
- end
118
-
119
- def visit_Mobility_Arel_Nodes_HstoreQuestion o, a
120
- json_infix o, a, '?'
121
- end
122
-
123
- private
124
-
125
- def json_infix o, a, opr
126
- visit(Nodes::Grouping.new(::Arel::Nodes::InfixOperation.new(opr, o.left, o.right)), a)
127
- end
128
- end
129
-
130
- ::Arel::Visitors::PostgreSQL.include Visitors
131
- end
132
- end
@@ -1,61 +0,0 @@
1
- # frozen-string-literal: true
2
- module Mobility
3
- module Arel
4
- class Visitor < ::Arel::Visitors::Visitor
5
- INNER_JOIN = ::Arel::Nodes::InnerJoin
6
- OUTER_JOIN = ::Arel::Nodes::OuterJoin
7
-
8
- attr_reader :backend_class, :locale
9
-
10
- def initialize(backend_class, locale)
11
- super()
12
- @backend_class, @locale = backend_class, locale
13
- end
14
-
15
- private
16
-
17
- def visit(*args)
18
- super
19
- rescue TypeError
20
- visit_default(*args)
21
- end
22
-
23
- def visit_collection(_objects)
24
- raise NotImplementedError
25
- end
26
- alias :visit_Array :visit_collection
27
-
28
- def visit_Arel_Nodes_Unary(object)
29
- visit(object.expr)
30
- end
31
-
32
- def visit_Arel_Nodes_Binary(object)
33
- visit_collection([object.left, object.right])
34
- end
35
-
36
- def visit_Arel_Nodes_Function(object)
37
- visit_collection(object.expressions)
38
- end
39
-
40
- def visit_Arel_Nodes_Case(object)
41
- visit_collection([object.case, object.conditions, object.default])
42
- end
43
-
44
- def visit_Arel_Nodes_And(object)
45
- visit_Array(object.children)
46
- end
47
-
48
- def visit_Arel_Nodes_Node(object)
49
- visit_default(object)
50
- end
51
-
52
- def visit_Arel_Attributes_Attribute(object)
53
- visit_default(object)
54
- end
55
-
56
- def visit_default(_object)
57
- nil
58
- end
59
- end
60
- end
61
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mobility
4
- module Sequel
5
- =begin
6
-
7
- Internal class used to force Sequel model to notice changes when mobility
8
- setter method is called.
9
-
10
- =end
11
- class ColumnChanges < Module
12
- # @param [Array<String>] attributes Backend attributes
13
- def initialize(attributes, column_affix: "%s")
14
- attributes.each do |attribute|
15
- define_method "#{attribute}=" do |value, **options|
16
- if !options[:super] && send(attribute) != value
17
- locale = options[:locale] || Mobility.locale
18
- column = (column_affix % attribute).to_sym
19
- attribute_with_locale = :"#{attribute}_#{Mobility.normalize_locale(locale)}"
20
- @changed_columns = changed_columns | [column, attribute.to_sym, attribute_with_locale]
21
- end
22
- super(value, **options)
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mobility
4
- module Sequel
5
- =begin
6
-
7
- Internal class used to initialize column value(s) by default to a hash.
8
-
9
- =end
10
- class HashInitializer < Module
11
- def initialize(*columns)
12
- class_eval <<-EOM, __FILE__, __LINE__ + 1
13
- def initialize_set(values)
14
- #{columns.map { |c| "self[:#{c}] = {}" }.join(';')}
15
- super
16
- end
17
- EOM
18
- end
19
- end
20
- end
21
- end
@@ -1,20 +0,0 @@
1
- module Mobility
2
- module Sequel
3
- =begin
4
-
5
- Module included in translation class dynamically generated by
6
- {Backends::Sequel::Table} backend.
7
-
8
- =end
9
- module ModelTranslation
10
- def self.included(base)
11
- base.plugin :validation_helpers
12
- end
13
-
14
- def validate
15
- super
16
- validates_presence [:locale]
17
- end
18
- end
19
- end
20
- end
@@ -1,16 +0,0 @@
1
- module Mobility
2
- module Sequel
3
- module SQL
4
- class QualifiedIdentifier < ::Sequel::SQL::QualifiedIdentifier
5
- attr_reader :backend_class, :locale, :attribute_name
6
-
7
- def initialize(table, column, locale, backend_class, attribute_name: nil)
8
- @backend_class = backend_class
9
- @locale = locale
10
- @attribute_name = attribute_name || column
11
- super(table, column)
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/sequel/translation"
3
-
4
- module Mobility
5
- module Sequel
6
- class StringTranslation < ::Sequel::Model(:mobility_string_translations)
7
- include Translation
8
- end
9
- end
10
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/sequel/translation"
3
-
4
- module Mobility
5
- module Sequel
6
- class TextTranslation < ::Sequel::Model(:mobility_text_translations)
7
- include Translation
8
- end
9
- end
10
- end
@@ -1,53 +0,0 @@
1
- module Mobility
2
- module Sequel
3
- module Translation
4
- def self.included(base)
5
- base.class_eval do
6
- plugin :validation_helpers
7
-
8
- # Paraphased from sequel_polymorphic gem
9
- #
10
- model = underscore(self.to_s)
11
- plural_model = pluralize(model)
12
- many_to_one :translatable,
13
- reciprocal: plural_model.to_sym,
14
- reciprocal_type: :many_to_one,
15
- setter: (proc do |able_instance|
16
- self[:translatable_id] = (able_instance.pk if able_instance)
17
- self[:translatable_type] = (able_instance.class.name if able_instance)
18
- end),
19
- dataset: (proc do
20
- translatable_type = send :translatable_type
21
- translatable_id = send :translatable_id
22
- return if translatable_type.nil? || translatable_id.nil?
23
- klass = self.class.send(:constantize, translatable_type)
24
- klass.where(klass.primary_key => translatable_id)
25
- end),
26
- eager_loader: (proc do |eo|
27
- id_map = {}
28
- eo[:rows].each do |model|
29
- model_able_type = model.send :translatable_type
30
- model_able_id = model.send :translatable_id
31
- model.associations[:translatable] = nil
32
- ((id_map[model_able_type] ||= {})[model_able_id] ||= []) << model if !model_able_type.nil? && !model_able_id.nil?
33
- end
34
- id_map.each do |klass_name, id_map|
35
- klass = constantize(camelize(klass_name))
36
- klass.where(klass.primary_key=>id_map.keys).all do |related_obj|
37
- id_map[related_obj.pk].each do |model|
38
- model.associations[:translatable] = related_obj
39
- end
40
- end
41
- end
42
- end)
43
-
44
- def validate
45
- super
46
- validates_presence [:locale, :key, :translatable_id, :translatable_type]
47
- validates_unique [:locale, :key, :translatable_id, :translatable_type]
48
- end
49
- end
50
- end
51
- end
52
- end
53
- end