mobility 0.6.0 → 0.7.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 +5 -5
- checksums.yaml.gz.sig +3 -2
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +39 -1
- data/Gemfile.lock +65 -10
- data/README.md +63 -27
- data/lib/mobility.rb +16 -31
- data/lib/mobility/active_record.rb +2 -12
- data/lib/mobility/active_record/uniqueness_validator.rb +9 -8
- data/lib/mobility/arel.rb +20 -0
- data/lib/mobility/arel/nodes.rb +16 -0
- data/lib/mobility/arel/nodes/pg_ops.rb +136 -0
- data/lib/mobility/arel/visitor.rb +61 -0
- data/lib/mobility/attributes.rb +82 -19
- data/lib/mobility/backend.rb +53 -8
- data/lib/mobility/backend_resetter.rb +2 -1
- data/lib/mobility/backends/active_record.rb +31 -11
- data/lib/mobility/backends/active_record/column.rb +7 -3
- data/lib/mobility/backends/active_record/container.rb +23 -21
- data/lib/mobility/backends/active_record/hstore.rb +11 -6
- data/lib/mobility/backends/active_record/json.rb +22 -16
- data/lib/mobility/backends/active_record/jsonb.rb +22 -16
- data/lib/mobility/backends/active_record/key_value.rb +123 -15
- data/lib/mobility/backends/active_record/pg_hash.rb +1 -2
- data/lib/mobility/backends/active_record/serialized.rb +7 -6
- data/lib/mobility/backends/active_record/table.rb +145 -24
- data/lib/mobility/backends/hash_valued.rb +15 -10
- data/lib/mobility/backends/key_value.rb +12 -12
- data/lib/mobility/backends/sequel/container.rb +3 -9
- data/lib/mobility/backends/sequel/hstore.rb +2 -2
- data/lib/mobility/backends/sequel/json.rb +15 -15
- data/lib/mobility/backends/sequel/jsonb.rb +14 -14
- data/lib/mobility/backends/sequel/key_value.rb +0 -11
- data/lib/mobility/backends/sequel/pg_hash.rb +2 -3
- data/lib/mobility/backends/sequel/pg_query_methods.rb +1 -1
- data/lib/mobility/backends/sequel/query_methods.rb +3 -3
- data/lib/mobility/backends/sequel/serialized.rb +2 -2
- data/lib/mobility/backends/sequel/table.rb +10 -11
- data/lib/mobility/backends/table.rb +17 -8
- data/lib/mobility/configuration.rb +4 -1
- data/lib/mobility/interface.rb +0 -0
- data/lib/mobility/plugins.rb +1 -0
- data/lib/mobility/plugins/active_record/query.rb +192 -0
- data/lib/mobility/plugins/cache.rb +1 -2
- data/lib/mobility/plugins/default.rb +28 -14
- data/lib/mobility/plugins/fallbacks.rb +1 -1
- data/lib/mobility/plugins/locale_accessors.rb +13 -9
- data/lib/mobility/plugins/presence.rb +15 -7
- data/lib/mobility/plugins/query.rb +28 -0
- data/lib/mobility/translates.rb +9 -9
- data/lib/mobility/version.rb +1 -1
- data/lib/rails/generators/mobility/templates/initializer.rb +1 -0
- metadata +10 -15
- metadata.gz.sig +0 -0
- data/lib/mobility/accumulator.rb +0 -33
- data/lib/mobility/adapter.rb +0 -20
- data/lib/mobility/backends/active_record/column/query_methods.rb +0 -42
- data/lib/mobility/backends/active_record/container/json_query_methods.rb +0 -36
- data/lib/mobility/backends/active_record/container/jsonb_query_methods.rb +0 -33
- data/lib/mobility/backends/active_record/hstore/query_methods.rb +0 -25
- data/lib/mobility/backends/active_record/json/query_methods.rb +0 -30
- data/lib/mobility/backends/active_record/jsonb/query_methods.rb +0 -26
- data/lib/mobility/backends/active_record/key_value/query_methods.rb +0 -76
- data/lib/mobility/backends/active_record/pg_query_methods.rb +0 -154
- data/lib/mobility/backends/active_record/serialized/query_methods.rb +0 -34
- data/lib/mobility/backends/active_record/table/query_methods.rb +0 -105
@@ -25,8 +25,7 @@ Internal class used by ActiveRecord backends backed by a Postgres data type
|
|
25
25
|
end
|
26
26
|
|
27
27
|
setup do |attributes, options = {}|
|
28
|
-
|
29
|
-
attributes.each { |attribute| store (affix % attribute), coder: Coder }
|
28
|
+
attributes.each { |attribute| store (options[:column_affix] % attribute), coder: Coder }
|
30
29
|
end
|
31
30
|
|
32
31
|
class Coder
|
@@ -30,25 +30,26 @@ Implements {Mobility::Backends::Serialized} backend for ActiveRecord models.
|
|
30
30
|
include ActiveRecord
|
31
31
|
include HashValued
|
32
32
|
|
33
|
-
require 'mobility/backends/active_record/serialized/query_methods'
|
34
|
-
|
35
33
|
# @!group Backend Configuration
|
36
34
|
# @param (see Backends::Serialized.configure)
|
37
35
|
# @option (see Backends::Serialized.configure)
|
38
36
|
# @raise (see Backends::Serialized.configure)
|
39
37
|
def self.configure(options)
|
38
|
+
super
|
40
39
|
Serialized.configure(options)
|
41
40
|
end
|
42
41
|
# @!endgroup
|
43
42
|
|
43
|
+
def self.build_node(attr, _locale)
|
44
|
+
raise ArgumentError,
|
45
|
+
"You cannot query on mobility attributes translated with the Serialized backend (#{attr})."
|
46
|
+
end
|
47
|
+
|
44
48
|
setup do |attributes, options|
|
45
49
|
coder = { yaml: YAMLCoder, json: JSONCoder }[options[:format]]
|
46
|
-
|
47
|
-
attributes.each { |attribute| serialize (column_affix % attribute), coder }
|
50
|
+
attributes.each { |attribute| serialize (options[:column_affix] % attribute), coder }
|
48
51
|
end
|
49
52
|
|
50
|
-
setup_query_methods(QueryMethods)
|
51
|
-
|
52
53
|
# @!group Cache Methods
|
53
54
|
# Returns column value as a hash
|
54
55
|
# @return [Hash]
|
@@ -19,7 +19,7 @@ If the translation table already exists, it will create a migration adding
|
|
19
19
|
columns to that table.
|
20
20
|
|
21
21
|
@example Model with table backend
|
22
|
-
class Post <
|
22
|
+
class Post < ApplicationRecord
|
23
23
|
extend Mobility
|
24
24
|
translates :title, backend: :table
|
25
25
|
end
|
@@ -92,28 +92,151 @@ columns to that table.
|
|
92
92
|
include ActiveRecord
|
93
93
|
include Table
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
95
|
+
class << self
|
96
|
+
# @!group Backend Configuration
|
97
|
+
# @option options [Symbol] association_name (:translations)
|
98
|
+
# Name of association method
|
99
|
+
# @option options [Symbol] table_name Name of translation table
|
100
|
+
# @option options [Symbol] foreign_key Name of foreign key
|
101
|
+
# @option options [Symbol] subclass_name (:Translation) Name of subclass
|
102
|
+
# to append to model class to generate translation class
|
103
|
+
def configure(options)
|
104
|
+
table_name = options[:model_class].table_name
|
105
|
+
options[:table_name] ||= "#{table_name.singularize}_translations"
|
106
|
+
options[:foreign_key] ||= table_name.downcase.singularize.camelize.foreign_key
|
107
|
+
if (association_name = options[:association_name]).present?
|
108
|
+
options[:subclass_name] ||= association_name.to_s.singularize.camelize.freeze
|
109
|
+
else
|
110
|
+
options[:association_name] = :translations
|
111
|
+
options[:subclass_name] ||= :Translation
|
112
|
+
end
|
113
|
+
%i[foreign_key association_name subclass_name table_name].each { |key| options[key] = options[key].to_sym }
|
114
|
+
end
|
115
|
+
# @!endgroup
|
116
|
+
|
117
|
+
# @param [String] attr Attribute name
|
118
|
+
# @param [Symbol] _locale Locale
|
119
|
+
# @return [Mobility::Arel::Attribute] Arel node for column on translation table
|
120
|
+
def build_node(attr, locale)
|
121
|
+
aliased_table = model_class.const_get(subclass_name).arel_table.alias(table_alias(locale))
|
122
|
+
Arel::Attribute.new(aliased_table, attr, locale, self)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Joins translations using either INNER/OUTER join appropriate to the
|
126
|
+
# query.
|
127
|
+
# @param [ActiveRecord::Relation] relation Relation to scope
|
128
|
+
# @param [Object] predicate Arel predicate
|
129
|
+
# @param [Symbol] locale Locale
|
130
|
+
# @option [Boolean] invert
|
131
|
+
# @return [ActiveRecord::Relation] relation Relation with joins applied (if needed)
|
132
|
+
def apply_scope(relation, predicate, locale, invert: false)
|
133
|
+
visitor = Visitor.new(self, locale)
|
134
|
+
if join_type = visitor.accept(predicate)
|
135
|
+
join_type &&= Visitor::INNER_JOIN if invert
|
136
|
+
join_translations(relation, locale, join_type)
|
137
|
+
else
|
138
|
+
relation
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def table_alias(locale)
|
145
|
+
"#{locale}_#{table_name}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def join_translations(relation, locale, join_type)
|
149
|
+
return relation if already_joined?(relation, locale, join_type)
|
150
|
+
m = model_class.arel_table
|
151
|
+
t = model_class.const_get(subclass_name).arel_table.alias(table_alias(locale))
|
152
|
+
relation.joins(m.join(t, join_type).
|
153
|
+
on(t[foreign_key].eq(m[:id]).
|
154
|
+
and(t[:locale].eq(locale))).join_sources)
|
155
|
+
end
|
156
|
+
|
157
|
+
def already_joined?(relation, locale, join_type)
|
158
|
+
if join = get_join(relation, locale)
|
159
|
+
return true if (join_type == Visitor::OUTER_JOIN) || (Visitor::INNER_JOIN === join)
|
160
|
+
relation.joins_values = relation.joins_values - [join]
|
161
|
+
end
|
162
|
+
false
|
163
|
+
end
|
164
|
+
|
165
|
+
def get_join(relation, locale)
|
166
|
+
relation.joins_values.find { |v| (::Arel::Nodes::Join === v) && (v.left.name == table_alias(locale).to_s) }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Internal class used to visit all nodes in a predicate clause and
|
171
|
+
# return a single join type required for the predicate, or nil if no
|
172
|
+
# join is required. (Similar to the KeyValue Visitor class.)
|
173
|
+
#
|
174
|
+
# Example:
|
175
|
+
#
|
176
|
+
# class Post < ApplicationRecord
|
177
|
+
# extend Mobility
|
178
|
+
# translates :title, :content, backend: :table
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# backend_class = Post.mobility_backend_class(:title)
|
182
|
+
# visitor = Mobility::Backends::ActiveRecord::Table::Visitor.new(backend_class)
|
183
|
+
#
|
184
|
+
# visitor.accept(title.eq(nil).and(content.eq(nil)))
|
185
|
+
# #=> Arel::Nodes::OuterJoin
|
186
|
+
#
|
187
|
+
# visitor.accept(title.eq("foo").and(content.eq(nil)))
|
188
|
+
# #=> Arel::Nodes::InnerJoin
|
189
|
+
#
|
190
|
+
# In the first case, both attributes are matched against nil values, so
|
191
|
+
# we need an OUTER JOIN. In the second case, one attribute is matched
|
192
|
+
# against a non-nil value, so we can use an INNER JOIN.
|
193
|
+
#
|
194
|
+
class Visitor < Arel::Visitor
|
195
|
+
private
|
196
|
+
|
197
|
+
def visit_Arel_Nodes_Equality(object)
|
198
|
+
nils, nodes = [object.left, object.right].partition(&:nil?)
|
199
|
+
if nodes.any?(&method(:visit))
|
200
|
+
nils.empty? ? INNER_JOIN : OUTER_JOIN
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def visit_collection(objects)
|
205
|
+
objects.map { |obj|
|
206
|
+
visit(obj).tap { |visited| return visited if visited == INNER_JOIN }
|
207
|
+
}.compact.first
|
208
|
+
end
|
209
|
+
alias :visit_Array :visit_collection
|
210
|
+
|
211
|
+
# If either left or right is an OUTER JOIN (predicate with a NULL
|
212
|
+
# argument) OR we are combining this with anything other than a
|
213
|
+
# column on the same translation table, we need to OUTER JOIN
|
214
|
+
# here. The *only* case where we can use an INNER JOIN is when we
|
215
|
+
# have predicates like this:
|
216
|
+
#
|
217
|
+
# table.attribute1 = 'something' OR table.attribute2 = 'somethingelse'
|
218
|
+
#
|
219
|
+
# Here, both columns are on the same table, and both are non-nil, so
|
220
|
+
# we can safely INNER JOIN. This is pretty subtle, think about it.
|
221
|
+
#
|
222
|
+
def visit_Arel_Nodes_Or(object)
|
223
|
+
visited = [object.left, object.right].map(&method(:visit))
|
224
|
+
if visited.all? { |v| INNER_JOIN == v }
|
225
|
+
INNER_JOIN
|
226
|
+
elsif visited.any?
|
227
|
+
OUTER_JOIN
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def visit_Mobility_Arel_Attribute(object)
|
232
|
+
# We compare table names here to ensure that attributes defined on
|
233
|
+
# different backends but the same table will correctly get an OUTER
|
234
|
+
# join when required. Use options[:table_name] here since we don't
|
235
|
+
# know if the other backend has a +table_name+ option accessor.
|
236
|
+
(backend_class.table_name == object.backend_class.options[:table_name]) &&
|
237
|
+
(locale == object.locale) && INNER_JOIN
|
113
238
|
end
|
114
|
-
%i[foreign_key association_name subclass_name table_name].each { |key| options[key] = options[key].to_sym }
|
115
239
|
end
|
116
|
-
# @!endgroup
|
117
240
|
|
118
241
|
setup do |_attributes, options|
|
119
242
|
association_name = options[:association_name]
|
@@ -143,7 +266,7 @@ columns to that table.
|
|
143
266
|
touch: true
|
144
267
|
|
145
268
|
before_save do
|
146
|
-
required_attributes = self.class.
|
269
|
+
required_attributes = self.class.mobility_attributes & translation_class.attribute_names
|
147
270
|
send(association_name).destroy_empty_translations(required_attributes)
|
148
271
|
end
|
149
272
|
|
@@ -159,8 +282,6 @@ columns to that table.
|
|
159
282
|
end
|
160
283
|
end
|
161
284
|
|
162
|
-
setup_query_methods(QueryMethods)
|
163
|
-
|
164
285
|
# Returns translation for a given locale, or builds one if none is present.
|
165
286
|
# @param [Symbol] locale
|
166
287
|
def translation_for(locale, _)
|
@@ -8,15 +8,9 @@ Defines read and write methods that access the value at a key with value
|
|
8
8
|
|
9
9
|
=end
|
10
10
|
module HashValued
|
11
|
-
# @!
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# @option options [Symbol] column_suffix Suffix added to generate column
|
15
|
-
# name from attribute name
|
16
|
-
def initialize(_model, _attribute, options = {})
|
17
|
-
super
|
18
|
-
@column_affix = "#{options[:column_prefix]}%s#{options[:column_suffix]}"
|
19
|
-
end
|
11
|
+
# @!method column_affix
|
12
|
+
# Returns interpolation string used to generate column names.
|
13
|
+
# @return [String] Affix to generate column names
|
20
14
|
|
21
15
|
# @!group Backend Accessors
|
22
16
|
#
|
@@ -36,10 +30,21 @@ Defines read and write methods that access the value at a key with value
|
|
36
30
|
translations.each { |l, _| yield l }
|
37
31
|
end
|
38
32
|
|
33
|
+
def self.included(backend_class)
|
34
|
+
backend_class.extend ClassMethods
|
35
|
+
backend_class.option_reader :column_affix
|
36
|
+
end
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
def configure(options)
|
40
|
+
options[:column_affix] = "#{options[:column_prefix]}%s#{options[:column_suffix]}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
39
44
|
private
|
40
45
|
|
41
46
|
def column_name
|
42
|
-
@column_name ||= (
|
47
|
+
@column_name ||= (column_affix % attribute)
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
@@ -46,15 +46,13 @@ other backends on model (otherwise one will overwrite the other).
|
|
46
46
|
module KeyValue
|
47
47
|
extend Backend::OrmDelegator
|
48
48
|
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
@association_name = options[:association_name]
|
57
|
-
end
|
49
|
+
# @!method association_name
|
50
|
+
# Returns the name of the polymorphic association.
|
51
|
+
# @return [Symbol] Name of the association
|
52
|
+
|
53
|
+
# @!method class_name
|
54
|
+
# Returns translation class used in polymorphic association.
|
55
|
+
# @return [Class] Translation class
|
58
56
|
|
59
57
|
# @!group Backend Accessors
|
60
58
|
# @!macro backend_reader
|
@@ -62,7 +60,7 @@ other backends on model (otherwise one will overwrite the other).
|
|
62
60
|
translation_for(locale, options).value
|
63
61
|
end
|
64
62
|
|
65
|
-
# @!macro
|
63
|
+
# @!macro backend_writer
|
66
64
|
def write(locale, value, options = {})
|
67
65
|
translation_for(locale, options).value = value
|
68
66
|
end
|
@@ -79,8 +77,10 @@ other backends on model (otherwise one will overwrite the other).
|
|
79
77
|
model.send(association_name)
|
80
78
|
end
|
81
79
|
|
82
|
-
def self.included(
|
83
|
-
|
80
|
+
def self.included(backend_class)
|
81
|
+
backend_class.extend ClassMethods
|
82
|
+
backend_class.option_reader :association_name
|
83
|
+
backend_class.option_reader :class_name
|
84
84
|
end
|
85
85
|
|
86
86
|
module ClassMethods
|
@@ -11,15 +11,9 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
|
|
11
11
|
require 'mobility/backends/sequel/container/json_query_methods'
|
12
12
|
require 'mobility/backends/sequel/container/jsonb_query_methods'
|
13
13
|
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
# @!macro backend_constructor
|
18
|
-
# @option options [Symbol] column_name Name of container column
|
19
|
-
def initialize(model, attribute, options = {})
|
20
|
-
super
|
21
|
-
@column_name = options[:column_name]
|
22
|
-
end
|
14
|
+
# @!method column_name
|
15
|
+
# @return [Symbol] (:translations) Name of translations column
|
16
|
+
option_reader :column_name
|
23
17
|
|
24
18
|
# @!group Backend Accessors
|
25
19
|
#
|
@@ -6,7 +6,7 @@ module Mobility
|
|
6
6
|
|
7
7
|
Implements the {Mobility::Backends::Hstore} backend for Sequel models.
|
8
8
|
|
9
|
-
@see Mobility::Backends::
|
9
|
+
@see Mobility::Backends::HashValued
|
10
10
|
|
11
11
|
=end
|
12
12
|
module Sequel
|
@@ -15,7 +15,7 @@ Implements the {Mobility::Backends::Hstore} backend for Sequel models.
|
|
15
15
|
|
16
16
|
# @!group Backend Accessors
|
17
17
|
# @!macro backend_reader
|
18
|
-
# @!method read(locale,
|
18
|
+
# @!method read(locale, options = {})
|
19
19
|
|
20
20
|
# @!group Backend Accessors
|
21
21
|
# @!macro backend_writer
|
@@ -6,7 +6,7 @@ module Mobility
|
|
6
6
|
|
7
7
|
Implements the {Mobility::Backends::Json} backend for Sequel models.
|
8
8
|
|
9
|
-
@see Mobility::Backends::
|
9
|
+
@see Mobility::Backends::HashValued
|
10
10
|
|
11
11
|
=end
|
12
12
|
module Sequel
|
@@ -15,21 +15,21 @@ Implements the {Mobility::Backends::Json} backend for Sequel models.
|
|
15
15
|
|
16
16
|
# @!group Backend Accessors
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
18
|
+
# @!method read(locale, options = {})
|
19
|
+
# @note Translation may be any json type, but querying will only work on
|
20
|
+
# string-typed values.
|
21
|
+
# @param [Symbol] locale Locale to read
|
22
|
+
# @param [Hash] options
|
23
|
+
# @return [String,Integer,Boolean] Value of translation
|
24
24
|
|
25
|
-
# @!
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# @!
|
25
|
+
# @!method write(locale, value, options = {})
|
26
|
+
# @note Translation may be any json type, but querying will only work
|
27
|
+
# on string-typed values.
|
28
|
+
# @param [Symbol] locale Locale to write
|
29
|
+
# @param [String,Integer,Boolean] value Value to write
|
30
|
+
# @param [Hash] options
|
31
|
+
# @return [String,Integer,Boolean] Updated value
|
32
|
+
# @!endgroup
|
33
33
|
|
34
34
|
setup_query_methods(QueryMethods)
|
35
35
|
end
|
@@ -6,7 +6,7 @@ module Mobility
|
|
6
6
|
|
7
7
|
Implements the {Mobility::Backends::Jsonb} backend for Sequel models.
|
8
8
|
|
9
|
-
@see Mobility::Backends::
|
9
|
+
@see Mobility::Backends::HashValued
|
10
10
|
|
11
11
|
=end
|
12
12
|
module Sequel
|
@@ -15,21 +15,21 @@ Implements the {Mobility::Backends::Jsonb} backend for Sequel models.
|
|
15
15
|
|
16
16
|
# @!group Backend Accessors
|
17
17
|
#
|
18
|
-
# @note Translation may be string, integer or boolean-valued since
|
19
|
-
# value is stored on a JSON hash.
|
20
|
-
# @param [Symbol] locale Locale to read
|
21
|
-
# @param [Hash] options
|
22
|
-
# @return [String,Integer,Boolean] Value of translation
|
23
18
|
# @!method read(locale, **options)
|
24
|
-
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# @param [Hash] options
|
31
|
-
# @return [String,Integer,Boolean] Updated value
|
19
|
+
# @note Translation may be string, integer or boolean-valued since
|
20
|
+
# value is stored on a JSON hash.
|
21
|
+
# @param [Symbol] locale Locale to read
|
22
|
+
# @param [Hash] options
|
23
|
+
# @return [String,Integer,Boolean] Value of translation
|
24
|
+
#
|
32
25
|
# @!method write(locale, value, **options)
|
26
|
+
# @note Translation may be string, integer or boolean-valued since
|
27
|
+
# value is stored on a JSON hash.
|
28
|
+
# @param [Symbol] locale Locale to write
|
29
|
+
# @param [String,Integer,Boolean] value Value to write
|
30
|
+
# @param [Hash] options
|
31
|
+
# @return [String,Integer,Boolean] Updated value
|
32
|
+
# @!endgroup
|
33
33
|
|
34
34
|
setup_query_methods(QueryMethods)
|
35
35
|
end
|