mobility 0.4.3 → 0.5.0

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 (83) 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 +11 -0
  5. data/Gemfile.lock +27 -27
  6. data/README.md +8 -8
  7. data/lib/mobility.rb +18 -5
  8. data/lib/mobility/{wrapper.rb → accumulator.rb} +2 -4
  9. data/lib/mobility/active_record.rb +1 -0
  10. data/lib/mobility/active_record/backend_resetter.rb +1 -0
  11. data/lib/mobility/active_record/string_translation.rb +1 -0
  12. data/lib/mobility/active_record/text_translation.rb +1 -0
  13. data/lib/mobility/adapter.rb +19 -0
  14. data/lib/mobility/attributes.rb +2 -1
  15. data/lib/mobility/backend.rb +1 -1
  16. data/lib/mobility/backend/orm_delegator.rb +5 -4
  17. data/lib/mobility/backend_resetter.rb +2 -0
  18. data/lib/mobility/backends/active_record/column.rb +1 -0
  19. data/lib/mobility/backends/active_record/column/query_methods.rb +1 -0
  20. data/lib/mobility/backends/active_record/container.rb +21 -4
  21. data/lib/mobility/backends/active_record/container/json_query_methods.rb +30 -0
  22. data/lib/mobility/backends/active_record/container/{query_methods.rb → jsonb_query_methods.rb} +4 -2
  23. data/lib/mobility/backends/active_record/json.rb +36 -0
  24. data/lib/mobility/backends/active_record/json/query_methods.rb +25 -0
  25. data/lib/mobility/backends/active_record/jsonb.rb +4 -4
  26. data/lib/mobility/backends/active_record/jsonb/query_methods.rb +1 -0
  27. data/lib/mobility/backends/active_record/key_value.rb +2 -2
  28. data/lib/mobility/backends/active_record/key_value/query_methods.rb +1 -0
  29. data/lib/mobility/backends/active_record/pg_hash.rb +1 -0
  30. data/lib/mobility/backends/active_record/pg_query_methods.rb +1 -1
  31. data/lib/mobility/backends/active_record/serialized.rb +1 -0
  32. data/lib/mobility/backends/active_record/serialized/query_methods.rb +1 -0
  33. data/lib/mobility/backends/active_record/table.rb +2 -2
  34. data/lib/mobility/backends/active_record/table/query_methods.rb +1 -0
  35. data/lib/mobility/backends/column.rb +2 -0
  36. data/lib/mobility/backends/json.rb +20 -0
  37. data/lib/mobility/backends/jsonb.rb +0 -1
  38. data/lib/mobility/backends/key_value.rb +1 -0
  39. data/lib/mobility/backends/sequel/column.rb +1 -0
  40. data/lib/mobility/backends/sequel/column/query_methods.rb +1 -0
  41. data/lib/mobility/backends/sequel/container.rb +19 -3
  42. data/lib/mobility/backends/sequel/container/json_query_methods.rb +34 -0
  43. data/lib/mobility/backends/sequel/container/{query_methods.rb → jsonb_query_methods.rb} +2 -1
  44. data/lib/mobility/backends/sequel/hstore/query_methods.rb +1 -0
  45. data/lib/mobility/backends/sequel/json.rb +36 -0
  46. data/lib/mobility/backends/sequel/json/query_methods.rb +27 -0
  47. data/lib/mobility/backends/sequel/jsonb/query_methods.rb +2 -1
  48. data/lib/mobility/backends/sequel/key_value.rb +3 -3
  49. data/lib/mobility/backends/sequel/key_value/query_methods.rb +1 -0
  50. data/lib/mobility/backends/sequel/pg_hash.rb +1 -0
  51. data/lib/mobility/backends/sequel/query_methods.rb +1 -0
  52. data/lib/mobility/backends/sequel/serialized.rb +1 -0
  53. data/lib/mobility/backends/sequel/serialized/query_methods.rb +1 -0
  54. data/lib/mobility/backends/sequel/table.rb +1 -0
  55. data/lib/mobility/backends/sequel/table/query_methods.rb +1 -0
  56. data/lib/mobility/backends/serialized.rb +1 -0
  57. data/lib/mobility/backends/table.rb +1 -0
  58. data/lib/mobility/configuration.rb +3 -5
  59. data/lib/mobility/fallbacks.rb +28 -0
  60. data/lib/mobility/plugins/active_model/dirty.rb +5 -5
  61. data/lib/mobility/plugins/active_record/dirty.rb +1 -1
  62. data/lib/mobility/plugins/cache.rb +1 -0
  63. data/lib/mobility/plugins/default.rb +2 -0
  64. data/lib/mobility/plugins/dirty.rb +1 -0
  65. data/lib/mobility/plugins/fallbacks.rb +3 -1
  66. data/lib/mobility/plugins/fallthrough_accessors.rb +4 -4
  67. data/lib/mobility/plugins/locale_accessors.rb +2 -2
  68. data/lib/mobility/plugins/presence.rb +1 -0
  69. data/lib/mobility/sequel/column_changes.rb +3 -1
  70. data/lib/mobility/sequel/hash_initializer.rb +2 -0
  71. data/lib/mobility/sequel/string_translation.rb +1 -0
  72. data/lib/mobility/sequel/text_translation.rb +1 -0
  73. data/lib/mobility/translates.rb +2 -0
  74. data/lib/mobility/util.rb +3 -1
  75. data/lib/mobility/version.rb +3 -1
  76. data/lib/rails/generators/mobility/active_record_migration_compatibility.rb +1 -0
  77. data/lib/rails/generators/mobility/backend_generators/base.rb +3 -3
  78. data/lib/rails/generators/mobility/generators.rb +1 -0
  79. data/lib/rails/generators/mobility/install_generator.rb +1 -0
  80. data/lib/rails/generators/mobility/templates/initializer.rb +75 -0
  81. data/lib/rails/generators/mobility/translations_generator.rb +3 -3
  82. metadata +14 -5
  83. metadata.gz.sig +0 -0
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require 'mobility/backends/active_record/pg_query_methods'
3
+ require "mobility/backends/active_record/query_methods"
4
+
5
+ module Mobility
6
+ module Backends
7
+ class ActiveRecord::Container::JsonQueryMethods < ActiveRecord::QueryMethods
8
+ include ActiveRecord::PgQueryMethods
9
+ attr_reader :column_name, :column
10
+
11
+ def initialize(_attributes, options)
12
+ super
13
+ @column_name = options[:column_name]
14
+ @column = arel_table[@column_name]
15
+ end
16
+
17
+ private
18
+
19
+ def matches(key, value, locale)
20
+ build_infix(:'->>',
21
+ build_infix(:'->', column, quote(locale)),
22
+ quote(key)).eq(value && value.to_s)
23
+ end
24
+
25
+ def has_locale(key, locale)
26
+ matches(key, nil, locale).not
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,8 +1,10 @@
1
- require "mobility/backends/active_record/jsonb"
1
+ # frozen_string_literal: true
2
+ require 'mobility/backends/active_record/pg_query_methods'
3
+ require "mobility/backends/active_record/query_methods"
2
4
 
3
5
  module Mobility
4
6
  module Backends
5
- class ActiveRecord::Container::QueryMethods < ActiveRecord::QueryMethods
7
+ class ActiveRecord::Container::JsonbQueryMethods < ActiveRecord::QueryMethods
6
8
  include ActiveRecord::PgQueryMethods
7
9
  attr_reader :column_name, :column
8
10
 
@@ -0,0 +1,36 @@
1
+ require 'mobility/backends/active_record/pg_hash'
2
+
3
+ module Mobility
4
+ module Backends
5
+ =begin
6
+
7
+ Implements the {Mobility::Backends::Json} backend for ActiveRecord models.
8
+
9
+ @see Mobility::Backends::ActiveRecord::HashValued
10
+
11
+ =end
12
+ class ActiveRecord::Json < ActiveRecord::PgHash
13
+ require 'mobility/backends/active_record/json/query_methods'
14
+
15
+ # @!group Backend Accessors
16
+ #
17
+ # @note Translation may be string, integer or boolean-valued since
18
+ # value is stored on a JSON hash.
19
+ # @param [Symbol] locale Locale to read
20
+ # @param [Hash] options
21
+ # @return [String,Integer,Boolean] Value of translation
22
+ # @!method read(locale, **options)
23
+
24
+ # @!group Backend Accessors
25
+ # @note Translation may be string, integer or boolean-valued since
26
+ # value is stored on a JSON hash.
27
+ # @param [Symbol] locale Locale to write
28
+ # @param [String,Integer,Boolean] value Value to write
29
+ # @param [Hash] options
30
+ # @return [String,Integer,Boolean] Updated value
31
+ # @!method write(locale, value, **options)
32
+
33
+ setup_query_methods(QueryMethods)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require 'mobility/backends/active_record/pg_query_methods'
3
+ require "mobility/backends/active_record/query_methods"
4
+
5
+ module Mobility
6
+ module Backends
7
+ class ActiveRecord::Json::QueryMethods < ActiveRecord::QueryMethods
8
+ include ActiveRecord::PgQueryMethods
9
+
10
+ private
11
+
12
+ def matches(key, value, locale)
13
+ build_locale_infix(key, locale).eq(value.to_s)
14
+ end
15
+
16
+ def has_locale(key, locale)
17
+ build_locale_infix(key, locale).eq(nil).not
18
+ end
19
+
20
+ def build_locale_infix(key, locale)
21
+ build_infix(:'->>', arel_table[key], quote(locale))
22
+ end
23
+ end
24
+ end
25
+ end
@@ -14,16 +14,16 @@ Implements the {Mobility::Backends::Jsonb} backend for ActiveRecord models.
14
14
 
15
15
  # @!group Backend Accessors
16
16
  #
17
- # @note Translation may be string, integer or boolean-valued since
18
- # value is stored on a JSON hash.
17
+ # @note Translation may be any json type, but querying will only work on
18
+ # string-typed values.
19
19
  # @param [Symbol] locale Locale to read
20
20
  # @param [Hash] options
21
21
  # @return [String,Integer,Boolean] Value of translation
22
22
  # @!method read(locale, **options)
23
23
 
24
24
  # @!group Backend Accessors
25
- # @note Translation may be string, integer or boolean-valued since
26
- # value is stored on a JSON hash.
25
+ # @note Translation may be any json type, but querying will only work on
26
+ # string-typed values.
27
27
  # @param [Symbol] locale Locale to write
28
28
  # @param [String,Integer,Boolean] value Value to write
29
29
  # @param [Hash] options
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mobility/backends/active_record/pg_query_methods'
2
3
  require "mobility/backends/active_record/query_methods"
3
4
 
@@ -38,7 +38,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
38
38
  def self.configure(options)
39
39
  super
40
40
  type = options[:type]
41
- options[:class_name] ||= Mobility::ActiveRecord.const_get("#{type.capitalize}Translation".freeze)
41
+ options[:class_name] ||= Mobility::ActiveRecord.const_get("#{type.capitalize}Translation")
42
42
  options[:class_name] = options[:class_name].constantize if options[:class_name].is_a?(String)
43
43
  options[:association_name] ||= :"#{options[:type]}_translations"
44
44
  %i[type association_name].each { |key| options[key] = options[key].to_sym }
@@ -103,7 +103,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
103
103
  # Clean up *all* leftover translations of this model, only once.
104
104
  def mobility_destroy_key_value_translations
105
105
  [:string, :text].freeze.each do |type|
106
- Mobility::ActiveRecord.const_get("#{type.capitalize}Translation".freeze).
106
+ Mobility::ActiveRecord.const_get("#{type.capitalize}Translation").
107
107
  where(translatable: self).destroy_all
108
108
  end
109
109
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/active_record/query_methods"
2
3
 
3
4
  module Mobility
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/active_record"
2
3
  require "mobility/backends/hash_valued"
3
4
 
@@ -103,7 +103,7 @@ code.
103
103
  end
104
104
 
105
105
  def build_infix(*args)
106
- Arel::Nodes::InfixOperation.new(*args)
106
+ arel_table.grouping(Arel::Nodes::InfixOperation.new(*args))
107
107
  end
108
108
 
109
109
  def quote(value)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/active_record"
2
3
  require "mobility/backends/hash_valued"
3
4
  require "mobility/backends/serialized"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/active_record/query_methods"
2
3
 
3
4
  module Mobility
@@ -101,7 +101,7 @@ columns to that table.
101
101
  # to append to model class to generate translation class
102
102
  def self.configure(options)
103
103
  table_name = options[:model_class].table_name
104
- options[:table_name] ||= "#{table_name.singularize}_translations".freeze
104
+ options[:table_name] ||= "#{table_name.singularize}_translations"
105
105
  options[:foreign_key] ||= table_name.downcase.singularize.camelize.foreign_key
106
106
  if (association_name = options[:association_name]).present?
107
107
  options[:subclass_name] ||= association_name.to_s.singularize.camelize.freeze
@@ -158,7 +158,7 @@ columns to that table.
158
158
  setup_query_methods(QueryMethods)
159
159
 
160
160
  def translation_for(locale, _)
161
- translation = translations.find { |t| t.locale == locale.to_s.freeze }
161
+ translation = translations.find { |t| t.locale == locale.to_s }
162
162
  translation ||= translations.build(locale: locale)
163
163
  translation
164
164
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/active_record/query_methods"
2
3
 
3
4
  module Mobility
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mobility
2
4
  module Backends
3
5
  =begin
@@ -0,0 +1,20 @@
1
+ module Mobility
2
+ module Backends
3
+ =begin
4
+
5
+ Stores translations as hash on Postgres json column.
6
+
7
+ ==Backend Options
8
+
9
+ This backend has no options.
10
+
11
+ @see Mobility::Backends::ActiveRecord::Json
12
+ @see Mobility::Backends::Sequel::Json
13
+ @see https://www.postgresql.org/docs/current/static/datatype-json.html PostgreSQL Documentation for JSON Types
14
+
15
+ =end
16
+ module Json
17
+ extend Backend::OrmDelegator
18
+ end
19
+ end
20
+ end
@@ -1,6 +1,5 @@
1
1
  module Mobility
2
2
  module Backends
3
-
4
3
  =begin
5
4
 
6
5
  Stores translations as hash on Postgres jsonb column.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/plugins/cache"
2
3
 
3
4
  module Mobility
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/sequel"
2
3
  require "mobility/backends/column"
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/sequel/query_methods"
2
3
 
3
4
  module Mobility
@@ -8,7 +8,8 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
8
8
  class Sequel::Container
9
9
  include Sequel
10
10
 
11
- require 'mobility/backends/sequel/container/query_methods'
11
+ require 'mobility/backends/sequel/container/json_query_methods'
12
+ require 'mobility/backends/sequel/container/jsonb_query_methods'
12
13
 
13
14
  # @return [Symbol] name of container column
14
15
  attr_reader :column_name
@@ -47,6 +48,12 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
47
48
  # @option options [Symbol] column_name (:translations) Name of column on which to store translations
48
49
  def self.configure(options)
49
50
  options[:column_name] ||= :translations
51
+ options[:column_name] = options[:column_name].to_sym
52
+ column_name, db_schema = options[:column_name], options[:model_class].db_schema
53
+ options[:column_type] = db_schema[column_name] && (db_schema[column_name][:db_type]).to_sym
54
+ unless %i[json jsonb].include?(options[:column_type])
55
+ raise InvalidColumnType, "#{options[:column_name]} must be a column of type json or jsonb"
56
+ end
50
57
  end
51
58
  # @!endgroup
52
59
  #
@@ -57,6 +64,8 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
57
64
  end
58
65
  end
59
66
 
67
+ backend_class = self
68
+
60
69
  setup do |attributes, options|
61
70
  column_name = options[:column_name]
62
71
  before_validation = Module.new do
@@ -73,9 +82,14 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
73
82
 
74
83
  plugin :defaults_setter
75
84
  attributes.each { |attribute| default_values[attribute.to_sym] = {} }
76
- end
77
85
 
78
- setup_query_methods(QueryMethods)
86
+ query_methods = backend_class.const_get("#{options[:column_type].capitalize}QueryMethods")
87
+ extend(Module.new do
88
+ define_method ::Mobility.query_method do
89
+ super().with_extend(query_methods.new(attributes, options))
90
+ end
91
+ end)
92
+ end
79
93
 
80
94
  private
81
95
 
@@ -94,6 +108,8 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
94
108
  end
95
109
  translations[locale.to_s][attribute] = value
96
110
  end
111
+
112
+ class InvalidColumnType < StandardError; end
97
113
  end
98
114
  end
99
115
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ require "mobility/backends/sequel/pg_query_methods"
3
+ require "mobility/backends/sequel/query_methods"
4
+
5
+ Sequel.extension :pg_json, :pg_json_ops
6
+
7
+ module Mobility
8
+ module Backends
9
+ class Sequel::Container::JsonQueryMethods < Sequel::QueryMethods
10
+ include Sequel::PgQueryMethods
11
+ attr_reader :column_name
12
+
13
+ def initialize(attributes, options)
14
+ super
15
+ @column_name = options[:column_name]
16
+ define_query_methods
17
+ end
18
+
19
+ private
20
+
21
+ def matches(key, value, locale)
22
+ build_op(column_name)[locale].get_text(key.to_s) =~ value.to_s
23
+ end
24
+
25
+ def has_locale(key, locale)
26
+ build_op(column_name)[locale].get_text(key.to_s) !~ nil
27
+ end
28
+
29
+ def build_op(key)
30
+ ::Sequel.pg_json_op(key)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "mobility/backends/sequel/pg_query_methods"
2
3
  require "mobility/backends/sequel/query_methods"
3
4
 
@@ -5,7 +6,7 @@ Sequel.extension :pg_json, :pg_json_ops
5
6
 
6
7
  module Mobility
7
8
  module Backends
8
- class Sequel::Container::QueryMethods < Sequel::QueryMethods
9
+ class Sequel::Container::JsonbQueryMethods < Sequel::QueryMethods
9
10
  include Sequel::PgQueryMethods
10
11
  attr_reader :column_name
11
12
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mobility/backends/sequel/pg_query_methods'
2
3
  require "mobility/backends/sequel/query_methods"
3
4
 
@@ -0,0 +1,36 @@
1
+ require 'mobility/backends/sequel/pg_hash'
2
+
3
+ module Mobility
4
+ module Backends
5
+ =begin
6
+
7
+ Implements the {Mobility::Backends::Json} backend for Sequel models.
8
+
9
+ @see Mobility::Backends::Sequel::HashValued
10
+
11
+ =end
12
+ class Sequel::Json < Sequel::PgHash
13
+ require 'mobility/backends/sequel/json/query_methods'
14
+
15
+ # @!group Backend Accessors
16
+ #
17
+ # @note Translation may be any json type, but querying will only work on
18
+ # string-typed values.
19
+ # @param [Symbol] locale Locale to read
20
+ # @param [Hash] options
21
+ # @return [String,Integer,Boolean] Value of translation
22
+ # @!method read(locale, **options)
23
+
24
+ # @!group Backend Accessors
25
+ # @note Translation may be any json type, but querying will only work on
26
+ # string-typed values.
27
+ # @param [Symbol] locale Locale to write
28
+ # @param [String,Integer,Boolean] value Value to write
29
+ # @param [Hash] options
30
+ # @return [String,Integer,Boolean] Updated value
31
+ # @!method write(locale, value, **options)
32
+
33
+ setup_query_methods(QueryMethods)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require "mobility/backends/sequel/pg_query_methods"
3
+ require "mobility/backends/sequel/query_methods"
4
+
5
+ Sequel.extension :pg_json, :pg_json_ops
6
+
7
+ module Mobility
8
+ module Backends
9
+ class Sequel::Json::QueryMethods < Sequel::QueryMethods
10
+ include Sequel::PgQueryMethods
11
+
12
+ private
13
+
14
+ def matches(key, value, locale)
15
+ build_op(key).get_text(locale) =~ value.to_s
16
+ end
17
+
18
+ def has_locale(key, locale)
19
+ build_op(key).get_text(locale) !~ nil
20
+ end
21
+
22
+ def build_op(key)
23
+ ::Sequel.pg_json_op(key)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,4 +1,5 @@
1
- require 'mobility/backends/sequel/pg_query_methods'
1
+ # frozen_string_literal: true
2
+ require "mobility/backends/sequel/pg_query_methods"
2
3
  require "mobility/backends/sequel/query_methods"
3
4
 
4
5
  Sequel.extension :pg_json, :pg_json_ops