mobility 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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