mobility 0.7.6 → 0.8.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 (52) 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 +14 -3
  5. data/Gemfile.lock +57 -0
  6. data/README.md +15 -4
  7. data/lib/mobility.rb +17 -1
  8. data/lib/mobility/active_record/uniqueness_validator.rb +1 -1
  9. data/lib/mobility/arel/nodes.rb +0 -3
  10. data/lib/mobility/arel/nodes/pg_ops.rb +0 -4
  11. data/lib/mobility/attributes.rb +42 -25
  12. data/lib/mobility/backends/active_record.rb +2 -2
  13. data/lib/mobility/backends/active_record/column.rb +2 -2
  14. data/lib/mobility/backends/active_record/key_value.rb +6 -9
  15. data/lib/mobility/backends/active_record/table.rb +6 -7
  16. data/lib/mobility/backends/column.rb +2 -2
  17. data/lib/mobility/backends/key_value.rb +5 -0
  18. data/lib/mobility/backends/sequel.rb +24 -11
  19. data/lib/mobility/backends/sequel/column.rb +4 -3
  20. data/lib/mobility/backends/sequel/container.rb +21 -12
  21. data/lib/mobility/backends/sequel/hstore.rb +11 -3
  22. data/lib/mobility/backends/sequel/json.rb +11 -3
  23. data/lib/mobility/backends/sequel/jsonb.rb +35 -3
  24. data/lib/mobility/backends/sequel/key_value.rb +97 -17
  25. data/lib/mobility/backends/sequel/serialized.rb +5 -4
  26. data/lib/mobility/backends/sequel/table.rb +95 -26
  27. data/lib/mobility/backends/table.rb +4 -0
  28. data/lib/mobility/configuration.rb +1 -1
  29. data/lib/mobility/plugins/active_record/query.rb +52 -26
  30. data/lib/mobility/plugins/locale_accessors.rb +3 -2
  31. data/lib/mobility/plugins/query.rb +3 -0
  32. data/lib/mobility/plugins/sequel/query.rb +140 -0
  33. data/lib/mobility/sequel.rb +0 -14
  34. data/lib/mobility/sequel/sql.rb +16 -0
  35. data/lib/mobility/version.rb +1 -1
  36. data/lib/rails/generators/mobility/templates/column_translations.rb +1 -1
  37. data/lib/rails/generators/mobility/templates/initializer.rb +3 -2
  38. data/lib/rails/generators/mobility/translations_generator.rb +1 -1
  39. metadata +27 -46
  40. metadata.gz.sig +1 -1
  41. data/lib/mobility/backends/active_record/query_methods.rb +0 -50
  42. data/lib/mobility/backends/sequel/column/query_methods.rb +0 -29
  43. data/lib/mobility/backends/sequel/container/json_query_methods.rb +0 -41
  44. data/lib/mobility/backends/sequel/container/jsonb_query_methods.rb +0 -41
  45. data/lib/mobility/backends/sequel/hstore/query_methods.rb +0 -34
  46. data/lib/mobility/backends/sequel/json/query_methods.rb +0 -34
  47. data/lib/mobility/backends/sequel/jsonb/query_methods.rb +0 -34
  48. data/lib/mobility/backends/sequel/key_value/query_methods.rb +0 -58
  49. data/lib/mobility/backends/sequel/pg_query_methods.rb +0 -114
  50. data/lib/mobility/backends/sequel/query_methods.rb +0 -36
  51. data/lib/mobility/backends/sequel/serialized/query_methods.rb +0 -22
  52. data/lib/mobility/backends/sequel/table/query_methods.rb +0 -58
@@ -1,34 +0,0 @@
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
- module Sequel
10
- class Jsonb::QueryMethods < QueryMethods
11
- include PgQueryMethods
12
-
13
- def matches(key, locale)
14
- build_op(key)[locale]
15
- end
16
-
17
- def exists(key, locale)
18
- build_op(key).has_key?(locale)
19
- end
20
-
21
- def quote(value)
22
- value && value.to_json
23
- end
24
-
25
- private
26
-
27
- def build_op(key)
28
- ::Sequel.pg_jsonb_op(column_name(key))
29
- end
30
- end
31
- Jsonb.private_constant :QueryMethods
32
- end
33
- end
34
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/backends/sequel/query_methods"
3
-
4
- module Mobility
5
- module Backends
6
- module Sequel
7
- class KeyValue::QueryMethods < QueryMethods
8
- def initialize(attributes, association_name: nil, class_name: nil, **)
9
- super
10
-
11
- define_join_method(association_name, class_name)
12
- define_query_methods(association_name)
13
- end
14
-
15
- private
16
-
17
- def define_join_method(association_name, translation_class)
18
- define_method :"join_#{association_name}" do |*attributes, **options|
19
- attributes.inject(self) do |relation, attribute|
20
- join_type = options[:outer_join] ? :left_outer : :inner
21
- relation.join_table(join_type,
22
- translation_class.table_name,
23
- {
24
- key: attribute.to_s,
25
- locale: Mobility.locale.to_s,
26
- translatable_type: model.name,
27
- translatable_id: ::Sequel[:"#{model.table_name}"][:id]
28
- },
29
- table_alias: "#{attribute}_#{association_name}")
30
- end
31
- end
32
- end
33
-
34
- def define_query_methods(association_name)
35
- q = self
36
-
37
- %w[exclude or where].each do |method_name|
38
- define_method method_name do |*conds, &block|
39
- if i18n_keys = q.extract_attributes(conds.first)
40
- cond = conds.first.dup
41
- i18n_nulls = i18n_keys.select { |key| cond[key].nil? }
42
- i18n_keys.each do |attr|
43
- cond[::Sequel[:"#{attr}_#{association_name}"][:value]] = q.collapse cond.delete(attr)
44
- end
45
- super(cond, &block).
46
- send("join_#{association_name}", *(i18n_keys - i18n_nulls), outer_join: method_name == "or").
47
- send("join_#{association_name}", *i18n_nulls, outer_join: true)
48
- else
49
- super(*conds, &block)
50
- end
51
- end
52
- end
53
- end
54
- end
55
- KeyValue.private_constant :QueryMethods
56
- end
57
- end
58
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mobility
4
- module Backends
5
- module Sequel
6
- =begin
7
-
8
- Internal module builder defining query methods for Postgres backends. Including
9
- class must define three methods:
10
-
11
- - a method +matches+ which takes a key (column name) and a locale to match and
12
- returns an SQL expression checking that the column has the specified value
13
- in the specified locale
14
- - a method +exists+ which takes a key (column name) and locale, and returns
15
- an SQL expression which checks that the column has a value in the locale
16
- - a method +quote+ which quotes the value to be matched
17
-
18
- (The +matches+/+exists+/+quote+ methods are implemented slightly differently
19
- for hstore/json/jsonb/container backends.)
20
-
21
- @see Mobility::Backends::Sequel::Json::QueryMethods
22
- @see Mobility::Backends::Sequel::Jsonb::QueryMethods
23
- @see Mobility::Backends::Sequel::Hstore::QueryMethods
24
- @see Mobility::Backends::Sequel::Container::JsonQueryMethods
25
- @see Mobility::Backends::Sequel::Container::JsonbQueryMethods
26
-
27
- =end
28
- module PgQueryMethods
29
- attr_reader :column_affix
30
-
31
- def initialize(attributes, options)
32
- super
33
- @column_affix = options[:column_affix]
34
- define_query_methods
35
- end
36
-
37
- # Create query for conditions and translated keys
38
- # @note This is a destructive action, it will alter +cond+.
39
- #
40
- # @param [Hash] cond Hash of attribute/value pairs
41
- # @param [Array] keys Translated attribute names
42
- # @param [Boolean] invert Invert query, true for +exclude+, false otherwise
43
- # @return [Sequel::SQL::Expression] Query expression
44
- def create_query!(cond, keys, invert = false)
45
- keys.map { |key|
46
- values = cond.delete(key)
47
- values = values.is_a?(Array) ? values.uniq: [values]
48
- create_query_op(key, values, invert)
49
- }.inject(invert ? :| : :&)
50
- end
51
-
52
- def matches(_key, _locale)
53
- raise NotImplementedError
54
- end
55
-
56
- def exists(_key, _locale)
57
- raise NotImplementedError
58
- end
59
-
60
- def quote(_value)
61
- raise NotImplementedError
62
- end
63
-
64
- private
65
-
66
- def define_query_methods
67
- %w[exclude or where].each do |method_name|
68
- define_query_method(method_name)
69
- end
70
- end
71
-
72
- def define_query_method(method_name)
73
- q = self
74
-
75
- define_method method_name do |*cond, &block|
76
- if i18n_keys = q.extract_attributes(cond.first)
77
- cond = cond.first
78
-
79
- query = q.create_query!(cond, i18n_keys, method_name == "exclude")
80
- if method_name == "or"
81
- query = ::Sequel.&(cond, query) unless cond.empty?
82
- super(query, &block)
83
- else
84
- super(cond, &block).where(query)
85
- end
86
- else
87
- super(*cond, &block)
88
- end
89
- end
90
- end
91
-
92
- def create_query_op(key, values, invert)
93
- locale = Mobility.locale.to_s
94
- values = values.map(&method(:quote))
95
- values = values.first if values.size == 1
96
-
97
- match = matches(key, locale) =~ values
98
-
99
- if invert
100
- exists(key, locale) & ~match
101
- else
102
- values.nil? ? ~exists(key, locale) : match
103
- end
104
- end
105
-
106
-
107
- def column_name(attribute)
108
- (column_affix % attribute).to_sym
109
- end
110
- end
111
- private_constant :PgQueryMethods
112
- end
113
- end
114
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/util"
3
-
4
- module Mobility
5
- module Backends
6
- module Sequel
7
- =begin
8
-
9
- Defines query method overrides to handle translated attributes for Sequel
10
- models. For details see backend-specific subclasses.
11
-
12
- =end
13
- class QueryMethods < Module
14
- # @param [Array<String>] attributes Translated attributes
15
- def initialize(attributes, _)
16
- @attributes = attributes.map(&:to_sym)
17
-
18
- @attributes.each do |attribute|
19
- define_method :"first_by_#{attribute}" do |value|
20
- where(attribute => value).select_all(model.table_name).first
21
- end
22
- end
23
- end
24
-
25
- def extract_attributes(cond)
26
- cond.is_a?(Hash) && Util.presence(cond.keys & @attributes)
27
- end
28
-
29
- def collapse(value)
30
- value.is_a?(Array) ? value.uniq : value
31
- end
32
- end
33
- private_constant :QueryMethods
34
- end
35
- end
36
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/backends/sequel/query_methods"
3
-
4
- module Mobility
5
- module Backends
6
- module Sequel
7
- class Serialized::QueryMethods < QueryMethods
8
- include Backends::Serialized
9
-
10
- def initialize(attributes, _)
11
- super
12
- q = self
13
-
14
- define_method :where do |*cond, &block|
15
- q.check_opts(cond.first) || super(*cond, &block)
16
- end
17
- end
18
- end
19
- Serialized.private_constant :QueryMethods
20
- end
21
- end
22
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
- require "mobility/backends/sequel/query_methods"
3
-
4
- module Mobility
5
- module Backends
6
- module Sequel
7
- class Table::QueryMethods < QueryMethods
8
- def initialize(attributes, association_name: nil, model_class: nil, subclass_name: nil, **options)
9
- super
10
- translation_class = model_class.const_get(subclass_name)
11
-
12
- define_join_method(association_name, translation_class, **options)
13
- define_query_methods(association_name, translation_class, **options)
14
- end
15
-
16
- def define_join_method(association_name, translation_class, table_name: nil, foreign_key: nil, **)
17
- define_method :"join_#{association_name}" do |**options|
18
- if joins = @opts[:join]
19
- # Return self if we've already joined this table
20
- return self if joins.any? { |clause| clause.table_expr == table_name }
21
- end
22
-
23
- join_type = options[:outer_join] ? :left_outer : :inner
24
- join_table(join_type,
25
- translation_class.table_name,
26
- {
27
- locale: Mobility.locale.to_s,
28
- foreign_key => ::Sequel[model.table_name][:id]
29
- })
30
- end
31
- end
32
-
33
- def define_query_methods(association_name, translation_class, **)
34
- q = self
35
-
36
- # See note in AR Table QueryMethods class about limitations of
37
- # query methods on translated attributes when searching on nil values.
38
- #
39
- %w[exclude or where].each do |method_name|
40
- define_method method_name do |*conds, &block|
41
- if i18n_keys = q.extract_attributes(conds.first)
42
- cond = conds.first.dup
43
- outer_join = method_name == "or" || i18n_keys.all? { |key| cond[key].nil? }
44
- i18n_keys.each do |attr|
45
- cond[::Sequel[translation_class.table_name][attr]] = q.collapse cond.delete(attr)
46
- end
47
- super(cond, &block).send("join_#{association_name}", outer_join: outer_join)
48
- else
49
- super(*conds, &block)
50
- end
51
- end
52
- end
53
- end
54
- end
55
- Table.private_constant :QueryMethods
56
- end
57
- end
58
- end