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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +14 -3
- data/Gemfile.lock +57 -0
- data/README.md +15 -4
- data/lib/mobility.rb +17 -1
- data/lib/mobility/active_record/uniqueness_validator.rb +1 -1
- data/lib/mobility/arel/nodes.rb +0 -3
- data/lib/mobility/arel/nodes/pg_ops.rb +0 -4
- data/lib/mobility/attributes.rb +42 -25
- data/lib/mobility/backends/active_record.rb +2 -2
- data/lib/mobility/backends/active_record/column.rb +2 -2
- data/lib/mobility/backends/active_record/key_value.rb +6 -9
- data/lib/mobility/backends/active_record/table.rb +6 -7
- data/lib/mobility/backends/column.rb +2 -2
- data/lib/mobility/backends/key_value.rb +5 -0
- data/lib/mobility/backends/sequel.rb +24 -11
- data/lib/mobility/backends/sequel/column.rb +4 -3
- data/lib/mobility/backends/sequel/container.rb +21 -12
- data/lib/mobility/backends/sequel/hstore.rb +11 -3
- data/lib/mobility/backends/sequel/json.rb +11 -3
- data/lib/mobility/backends/sequel/jsonb.rb +35 -3
- data/lib/mobility/backends/sequel/key_value.rb +97 -17
- data/lib/mobility/backends/sequel/serialized.rb +5 -4
- data/lib/mobility/backends/sequel/table.rb +95 -26
- data/lib/mobility/backends/table.rb +4 -0
- data/lib/mobility/configuration.rb +1 -1
- data/lib/mobility/plugins/active_record/query.rb +52 -26
- data/lib/mobility/plugins/locale_accessors.rb +3 -2
- data/lib/mobility/plugins/query.rb +3 -0
- data/lib/mobility/plugins/sequel/query.rb +140 -0
- data/lib/mobility/sequel.rb +0 -14
- data/lib/mobility/sequel/sql.rb +16 -0
- data/lib/mobility/version.rb +1 -1
- data/lib/rails/generators/mobility/templates/column_translations.rb +1 -1
- data/lib/rails/generators/mobility/templates/initializer.rb +3 -2
- data/lib/rails/generators/mobility/translations_generator.rb +1 -1
- metadata +27 -46
- metadata.gz.sig +1 -1
- data/lib/mobility/backends/active_record/query_methods.rb +0 -50
- data/lib/mobility/backends/sequel/column/query_methods.rb +0 -29
- data/lib/mobility/backends/sequel/container/json_query_methods.rb +0 -41
- data/lib/mobility/backends/sequel/container/jsonb_query_methods.rb +0 -41
- data/lib/mobility/backends/sequel/hstore/query_methods.rb +0 -34
- data/lib/mobility/backends/sequel/json/query_methods.rb +0 -34
- data/lib/mobility/backends/sequel/jsonb/query_methods.rb +0 -34
- data/lib/mobility/backends/sequel/key_value/query_methods.rb +0 -58
- data/lib/mobility/backends/sequel/pg_query_methods.rb +0 -114
- data/lib/mobility/backends/sequel/query_methods.rb +0 -36
- data/lib/mobility/backends/sequel/serialized/query_methods.rb +0 -22
- 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
|