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