nobrainer 0.34.1 → 0.41.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad996bff8cfeced8ef2da26c7b989d24138bb5e4c9a7aa53738cd2cbdfdd907c
4
- data.tar.gz: a24979230bc5d9deeb4dfbee4f353de22a61037dddff0e97521a8d72380db9af
3
+ metadata.gz: 477e66e4e3380775847ce79e706f50a04134e7e87002b31aa0ca33c9e164d9d7
4
+ data.tar.gz: b303bbb3dc6a45df84f39edd2cce6d26af27000939c56be05e8f036c0ad11e76
5
5
  SHA512:
6
- metadata.gz: c3fbe68aa20b186aaca5b5981c476754a9f3cb7e238d09db17340a348f983d48518e34927064cd124640b5dd47564406893613b2a39487b90712e7e02a5bcd58
7
- data.tar.gz: 34106b6e8c1be3260dc8e6356c0658deaabff758818def9aafead00445c2ffcb8b93f8c6b261b4d1d6555d0e5dae0f8c97aad1e123c583933b79eda283849791
6
+ metadata.gz: f1f883d15467994b72aabddbb61adcadd7095a5220f89ad1b4d8e58cf6927cfb7a99e0e1443fc24d7edf37bf4a24c24e95d0bc99c47d39281b0e56c73ee549b0
7
+ data.tar.gz: '04592d9c64732b25089dccd897ad451cd2f71b12a96a93532604768c9c40c1757e6f2b528792976f8be054e376d0a3a4541ca3a3aa7de60014a7e88d97e10453'
data/CHANGELOG.md CHANGED
@@ -6,6 +6,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+
10
+ ## [0.41.0] - 2021-10-17
11
+ ### Added
12
+ - ActiveRecord `store_accessor` helper method
13
+
14
+ ### Fixed
15
+ - gemspec dependencies on activemodel and activesupport
16
+
17
+ ## [0.40.0] - 2021-10-16
18
+ ### Fixed
19
+ - Ruby 3 compatibility
20
+ - Test Ruby 3 + Rails 7 alpha2 on Travis CI
21
+
22
+ ## [0.36.0] - 2021-08-08
23
+ ### Added
24
+ - Array and TypedArray types for validation and serialization
25
+
26
+ ## [0.35.0] - 2021-08-08
27
+ ### Added
28
+ - Dockerfile, docker-compose and Earthfile
29
+ - Test Ruby 3 + Rails 6 on Travis CI
30
+ - Implements the ReQL `during` command
31
+
9
32
  ## [0.34.1] - 2021-02-18
10
33
  ### Fixed
11
34
  - Defining attributes at class level (Rails 6.1 compatibity)
@@ -93,7 +116,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
93
116
  - Locks: bug fix: allow small timeouts in lock()
94
117
  - Fix reentrant lock counter on steals
95
118
 
96
- [Unreleased]: https://github.com/nobrainerorm/nobrainer/compare/v0.34.1...HEAD
119
+ [Unreleased]: https://github.com/nobrainerorm/nobrainer/compare/v0.41.0...HEAD
120
+ [0.41.0]: https://github.com/nobrainerorm/nobrainer/compare/v0.40.0...v0.41.0
121
+ [0.40.0]: https://github.com/nobrainerorm/nobrainer/compare/v0.36.0...v0.40.0
122
+ [0.36.0]: https://github.com/nobrainerorm/nobrainer/compare/v0.35.0...v0.36.0
123
+ [0.35.0]: https://github.com/nobrainerorm/nobrainer/compare/v0.34.1...v0.35.0
97
124
  [0.34.1]: https://github.com/nobrainerorm/nobrainer/compare/v0.34.0...v0.34.1
98
125
  [0.34.0]: https://github.com/nobrainerorm/nobrainer/compare/v0.33.0...v0.34.0
99
126
  [0.33.0]: https://github.com/nobrainerorm/nobrainer/compare/v0.32.0...v0.33.0
@@ -104,6 +104,7 @@ module NoBrainer::Criteria::Where
104
104
  when :between then [key_modifier, op, (cast_value(value.min)..cast_value(value.max))]
105
105
  when :include then ensure_scalar_for(op); [:any, :eq, cast_value(value)]
106
106
  when :defined, :undefined then ensure_scalar_for(op); [key_modifier, op, cast_value(value)]
107
+ when :during then [key_modifier, op, [cast_value(value.first), cast_value(value.last)]]
107
108
  else [key_modifier, op, cast_value(value)]
108
109
  end
109
110
  BinaryOperator.new(new_key_path, new_key_modifier, new_op, new_value, model, true)
@@ -132,6 +133,7 @@ module NoBrainer::Criteria::Where
132
133
  when :between then (lvalue >= value.min) & (lvalue <= value.max)
133
134
  when :in then RethinkDB::RQL.new.expr(value).contains(lvalue)
134
135
  when :intersects then lvalue.intersects(value.to_rql)
136
+ when :during then lvalue.during(value.first, value.last)
135
137
  when :near
136
138
  # XXX options[:max_results] is not used, seems to be a workaround of rethinkdb index implementation.
137
139
  circle = value[:circle]
@@ -244,6 +246,7 @@ module NoBrainer::Criteria::Where
244
246
  when Symbol::Decoration
245
247
  case clause.args.size
246
248
  when 1 then parse_clause_stub(clause, clause.args.first, options)
249
+ when 2 then parse_clause_stub(clause, clause.args, options)
247
250
  else raise "Invalid argument: #{clause}"
248
251
  end
249
252
  else raise "Invalid clause: #{clause}"
@@ -263,6 +266,11 @@ module NoBrainer::Criteria::Where
263
266
  else instantiate_binary_op(key.to_sym, :eq, value, options)
264
267
  end
265
268
  when Symbol::Decoration then
269
+ # The :eq operator can have only one arg
270
+ if key.decorator == :eq && value.is_a?(Array) && value.size > 1
271
+ raise "Invalid key: #{key}"
272
+ end
273
+
266
274
  case key.decorator
267
275
  when :any, :all, :not then instantiate_binary_op(key, :eq, value, options)
268
276
  when :gte then instantiate_binary_op(key.symbol, :ge, value, options)
@@ -33,8 +33,12 @@ module NoBrainer::Document::Association::EagerLoader
33
33
  def eager_load_association(docs, association_name, criteria=nil)
34
34
  docs = docs.compact
35
35
  return [] if docs.empty?
36
- meta = docs.first.root_class.association_metadata
37
- association = meta[association_name.to_sym] || meta[association_name.to_s.singularize.to_sym]
36
+
37
+ meta = docs.first.class.association_metadata
38
+ root_meta = docs.first.root_class.association_metadata
39
+ association = meta[association_name.to_sym] || root_meta[association_name.to_sym] ||
40
+ meta[association_name.to_s.singularize.to_sym] || root_meta[association_name.to_s.singularize.to_sym]
41
+
38
42
  raise "Unknown association #{association_name}" unless association
39
43
  association.eager_load(docs, criteria)
40
44
  end
@@ -0,0 +1,304 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/hash/indifferent_access'
4
+
5
+ module NoBrainer
6
+ module Document
7
+ # Store gives you a way for storing hashes in a single field with accessors
8
+ # to the Hash keys.
9
+ # It is a portage of the ActiveRecord::Store which make gems using it
10
+ # compatible with NoBrainer.
11
+ #
12
+ # You can then declare accessors to this store that are then accessible just
13
+ # like any other attribute of the model. This is very helpful for easily
14
+ # exposing store keys to a form or elsewhere that's already built around
15
+ # just accessing attributes on the model.
16
+ #
17
+ # Every accessor comes with dirty tracking methods (+key_changed?+,
18
+ # +key_was+ and +key_change+).
19
+ #
20
+ # You can set custom coder to encode/decode your serialized attributes
21
+ # to/from different formats.
22
+ # JSON, YAML, Marshal are supported out of the box.
23
+ # Generally it can be any wrapper that provides +load+ and +dump+.
24
+ #
25
+ # NOTE: The {.store}[rdoc-ref:rdoc-ref:ClassMethods#store] method is here
26
+ # for compatibility reason, but you should use
27
+ # {.store_accessor}[rdoc-ref:ClassMethods#store_accessor] instead
28
+ # to generate the accessor methods.
29
+ # Be aware that these columns use a string keyed hash and do not allow
30
+ # access using a symbol.
31
+ #
32
+ # NOTE: The default validations with the exception of +uniqueness+ will work.
33
+ #
34
+ # Examples:
35
+ #
36
+ # class User
37
+ # include NoBrainer::Document
38
+ #
39
+ # store :settings, accessors: [ :color, :homepage ], coder: JSON
40
+ # store :parent, accessors: [ :name ], coder: JSON, prefix: true
41
+ # store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner
42
+ # store :settings, accessors: [ :two_factor_auth ], suffix: true
43
+ # store :settings, accessors: [ :login_retry ], suffix: :config
44
+ # end
45
+ #
46
+ # u = User.new(color: 'black', homepage: '37signals.com',
47
+ # parent_name: 'Mary', partner_name: 'Lily')
48
+ # u.color # Accessor stored attribute
49
+ # u.parent_name # Accessor stored attribute with prefix
50
+ # u.partner_name # Accessor stored attribute with custom prefix
51
+ # u.two_factor_auth_settings # Accessor stored attribute with suffix
52
+ # u.login_retry_config # Accessor stored attribute with custom suffix
53
+ # u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
54
+ #
55
+ # # There is no difference between strings and symbols for accessing
56
+ # # custom attributes
57
+ # u.settings[:country] # => 'Denmark'
58
+ # u.settings['country'] # => 'Denmark'
59
+ #
60
+ # # Dirty tracking
61
+ # u.color = 'green'
62
+ # u.color_changed? # => true
63
+ # u.color_was # => 'black'
64
+ # u.color_change # => ['black', 'red']
65
+ #
66
+ # # Add additional accessors to an existing store through store_accessor
67
+ # class SuperUser < User
68
+ # store_accessor :settings, :privileges, :servants
69
+ # store_accessor :parent, :birthday, prefix: true
70
+ # store_accessor :settings, :secret_question, suffix: :config
71
+ # end
72
+ #
73
+ # The stored attribute names can be retrieved using
74
+ # {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
75
+ #
76
+ # User.stored_attributes[:settings]
77
+ # #=> [:color, :homepage, :two_factor_auth, :login_retry]
78
+ #
79
+ # == Overwriting default accessors
80
+ #
81
+ # All stored values are automatically available through accessors on
82
+ # the NoBrainer Document object, but sometimes you want to specialize
83
+ # this behavior. This can be done by overwriting the default accessors
84
+ # (using the same name as the attribute) and calling <tt>super</tt>
85
+ # to actually change things.
86
+ #
87
+ # class Song
88
+ # include NoBrainer::Document
89
+ #
90
+ # # Uses a stored integer to hold the volume adjustment of the song
91
+ # store :settings, accessors: [:volume_adjustment]
92
+ #
93
+ # def volume_adjustment=(decibels)
94
+ # super(decibels.to_i)
95
+ # end
96
+ #
97
+ # def volume_adjustment
98
+ # super.to_i
99
+ # end
100
+ # end
101
+ module Store
102
+ extend ActiveSupport::Concern
103
+
104
+ included do
105
+ class << self
106
+ attr_accessor :local_stored_attributes
107
+ end
108
+ end
109
+
110
+ module ClassMethods
111
+ def store(store_attribute, options = {})
112
+ store_accessor(store_attribute, options[:accessors], **options.slice(:prefix, :suffix)) if options.has_key? :accessors
113
+ end
114
+
115
+ def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil)
116
+ keys = keys.flatten
117
+
118
+ accessor_prefix =
119
+ case prefix
120
+ when String, Symbol
121
+ "#{prefix}_"
122
+ when TrueClass
123
+ "#{store_attribute}_"
124
+ else
125
+ ""
126
+ end
127
+ accessor_suffix =
128
+ case suffix
129
+ when String, Symbol
130
+ "_#{suffix}"
131
+ when TrueClass
132
+ "_#{store_attribute}"
133
+ else
134
+ ""
135
+ end
136
+
137
+ field store_attribute, type: Hash, default: {} unless has_field?(store_attribute)
138
+
139
+ define_method("#{store_attribute}=") do |value|
140
+ super(value) if value.is_a?(Hash) || value.nil?
141
+ end
142
+
143
+ _store_accessors_module.module_eval do
144
+ keys.each do |key|
145
+ accessor_key = "#{accessor_prefix}#{key}#{accessor_suffix}"
146
+
147
+ define_method("#{accessor_key}=") do |value|
148
+ write_store_attribute(store_attribute, key, value)
149
+ end
150
+
151
+ define_method(accessor_key) do
152
+ read_store_attribute(store_attribute, key)
153
+ end
154
+
155
+ define_method("#{accessor_key}_changed?") do
156
+ return false unless __send__("#{store_attribute}_changed?")
157
+ prev_store, new_store = changes[store_attribute]
158
+ if NoBrainer.rails4?
159
+ (prev_store && prev_store[key.to_s]) != (new_store && new_store[key.to_s])
160
+ else
161
+ (prev_store && prev_store.dig(key)) != (new_store && new_store.dig(key))
162
+ end
163
+ end
164
+
165
+ define_method("#{accessor_key}_change") do
166
+ return unless __send__("#{store_attribute}_changed?")
167
+ prev_store, new_store = changes[store_attribute]
168
+ if NoBrainer.rails4?
169
+ [(prev_store && prev_store[key.to_s]), (new_store && new_store[key.to_s])]
170
+ else
171
+ [(prev_store && prev_store.dig(key)), (new_store && new_store.dig(key))]
172
+ end
173
+ end
174
+
175
+ define_method("#{accessor_key}_was") do
176
+ return unless __send__("#{store_attribute}_changed?")
177
+ prev_store, _new_store = changes[store_attribute]
178
+ if NoBrainer.rails4?
179
+ (prev_store && prev_store[key.to_s])
180
+ else
181
+ (prev_store && prev_store.dig(key))
182
+ end
183
+ end
184
+
185
+ # NoBrainer doesn't have `attribute_will_change!` so those methods
186
+ # can't be implemented yet.
187
+ # See https://github.com/NoBrainerORM/nobrainer/pull/190
188
+ #
189
+ # define_method("saved_change_to_#{accessor_key}?") do
190
+ # return false unless __send__("saved_change_to_#{store_attribute}?")
191
+ # prev_store, new_store = __send__("saved_change_to_#{store_attribute}")
192
+ # prev_store&.dig(key) != new_store&.dig(key)
193
+ # end
194
+
195
+ # define_method("saved_change_to_#{accessor_key}") do
196
+ # return unless __send__("saved_change_to_#{store_attribute}?")
197
+ # prev_store, new_store = __send__("saved_change_to_#{store_attribute}")
198
+ # [prev_store&.dig(key), new_store&.dig(key)]
199
+ # end
200
+
201
+ # define_method("#{accessor_key}_before_last_save") do
202
+ # return unless __send__("saved_change_to_#{store_attribute}?")
203
+ # prev_store, _new_store = __send__("saved_change_to_#{store_attribute}")
204
+ # prev_store&.dig(key)
205
+ # end
206
+ end
207
+ end
208
+
209
+ # assign new store attribute and create new hash to ensure that each class in the hierarchy
210
+ # has its own hash of stored attributes.
211
+ self.local_stored_attributes ||= {}
212
+ self.local_stored_attributes[store_attribute] ||= []
213
+ self.local_stored_attributes[store_attribute] |= keys
214
+ end
215
+
216
+ def _store_accessors_module # :nodoc:
217
+ @_store_accessors_module ||= begin
218
+ mod = Module.new
219
+ include mod
220
+ mod
221
+ end
222
+ end
223
+
224
+ def stored_attributes
225
+ parent = superclass.respond_to?(:stored_attributes) ? superclass.stored_attributes : {}
226
+ if local_stored_attributes
227
+ parent.merge!(local_stored_attributes) { |k, a, b| a | b }
228
+ end
229
+ parent
230
+ end
231
+ end
232
+
233
+ private
234
+
235
+ def read_store_attribute(store_attribute, key) # :doc:
236
+ StringKeyedHashAccessor.read(self, store_attribute, key)
237
+ end
238
+
239
+ def write_store_attribute(store_attribute, key, value) # :doc:
240
+ StringKeyedHashAccessor.write(self, store_attribute, key, value)
241
+ end
242
+
243
+ class HashAccessor # :nodoc:
244
+ def self.read(object, attribute, key)
245
+ prepare(object, attribute)
246
+ object.public_send(attribute)[key]
247
+ end
248
+
249
+ def self.write(object, attribute, key, value)
250
+ prepare(object, attribute)
251
+ if value != read(object, attribute, key)
252
+ # "#{attribute}_will_change!" is not implemented in NoBrainer. See issue #190
253
+ # object.public_send :"#{attribute}_will_change!"
254
+ object.public_send(attribute)[key] = value
255
+ end
256
+ end
257
+
258
+ def self.prepare(object, attribute)
259
+ object.public_send :"#{attribute}=", {} unless object.send(attribute)
260
+ end
261
+ end
262
+
263
+ class StringKeyedHashAccessor < HashAccessor # :nodoc:
264
+ def self.read(object, attribute, key)
265
+ super object, attribute, key.to_s
266
+ end
267
+
268
+ def self.write(object, attribute, key, value)
269
+ super object, attribute, key.to_s, value
270
+ end
271
+ end
272
+
273
+ class IndifferentCoder # :nodoc:
274
+ def initialize(attr_name, coder_or_class_name)
275
+ @coder =
276
+ if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
277
+ coder_or_class_name
278
+ else
279
+ NoBrainer::Document::Coders::YAMLColumn.new(attr_name, coder_or_class_name || Object)
280
+ end
281
+ end
282
+
283
+ def dump(obj)
284
+ @coder.dump self.class.as_indifferent_hash(obj)
285
+ end
286
+
287
+ def load(yaml)
288
+ self.class.as_indifferent_hash(@coder.load(yaml || ""))
289
+ end
290
+
291
+ def self.as_indifferent_hash(obj)
292
+ case obj
293
+ when ActiveSupport::HashWithIndifferentAccess
294
+ obj
295
+ when Hash
296
+ obj.with_indifferent_access
297
+ else
298
+ ActiveSupport::HashWithIndifferentAccess.new
299
+ end
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,90 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
3
+ module NoBrainer
4
+ class Array < ::Array
5
+ # delegate cast to each array element
6
+ def self.nobrainer_cast_user_to_model(values)
7
+ ::Array.wrap(values).map do |value|
8
+ if value.class.respond_to?(:nobrainer_cast_user_to_model)
9
+ value.class.nobrainer_cast_user_to_model(value)
10
+ else
11
+ value
12
+ end
13
+ end
14
+ end
15
+
16
+ # delegate cast to each array element
17
+ def self.nobrainer_cast_model_to_db(values)
18
+ ::Array.wrap(values).map do |value|
19
+ if value.class.respond_to?(:nobrainer_cast_model_to_db)
20
+ value.class.nobrainer_cast_model_to_db(value)
21
+ else
22
+ value
23
+ end
24
+ end
25
+ end
26
+
27
+ # delegate cast to each array element
28
+ def self.nobrainer_cast_db_to_model(values)
29
+ ::Array.wrap(values).map do |value|
30
+ if value.class.respond_to?(:nobrainer_cast_db_to_model)
31
+ value.class.nobrainer_cast_db_to_model(method, value)
32
+ else
33
+ value
34
+ end
35
+ end
36
+ end
37
+
38
+ # convenience method to create a TypedArray
39
+ def self.of(object_type = nil, **options)
40
+ NoBrainer::TypedArray.of(object_type, **options)
41
+ end
42
+ end
43
+
44
+ class TypedArray < Array
45
+ def self.of(object_type, allow_nil: false)
46
+ NoBrainer::Document::Types.load_type_extensions(object_type)
47
+ ::Class.new(TypedArray) do
48
+ define_singleton_method(:object_type) { object_type }
49
+ define_singleton_method(:allow_nil?) { allow_nil }
50
+ end
51
+ end
52
+
53
+ def self.name
54
+ str = String.new "Array"
55
+ str += "(#{object_type.name})" if respond_to?(:object_type)
56
+ str
57
+ end
58
+
59
+ # delegate cast methods to object_type cast methods, if defined
60
+ def self.nobrainer_cast_user_to_model(values)
61
+ cast_type = object_type.respond_to?(:nobrainer_cast_user_to_model) && object_type
62
+ values = ::Array.wrap(values).map do |value|
63
+ value = cast_type.nobrainer_cast_user_to_model(value) if cast_type
64
+ unless (value.nil? && allow_nil?) || value.is_a?(object_type)
65
+ raise NoBrainer::Error::InvalidType, type: object_type.name, value: value
66
+ end
67
+ value
68
+ end
69
+ new(values)
70
+ end
71
+
72
+ def self.nobrainer_cast_model_to_db(values)
73
+ values = ::Array.wrap(values)
74
+ if object_type.respond_to?(:nobrainer_cast_model_to_db)
75
+ values.map { |value| object_type.nobrainer_cast_model_to_db(value) }
76
+ else
77
+ values
78
+ end
79
+ end
80
+
81
+ def self.nobrainer_cast_db_to_model(values)
82
+ values = ::Array.wrap(values)
83
+ if object_type.respond_to?(:nobrainer_cast_db_to_model)
84
+ values.map { |value| object_type.nobrainer_cast_db_to_model(value) }
85
+ else
86
+ values
87
+ end
88
+ end
89
+ end
90
+ end
@@ -9,7 +9,7 @@ module NoBrainer::Document::Types
9
9
  def add_type_errors
10
10
  return unless @pending_type_errors
11
11
  @pending_type_errors.each do |name, error|
12
- errors.add(name, :invalid_type, error.error)
12
+ errors.add(name, :invalid_type, **error.error)
13
13
  end
14
14
  end
15
15
 
@@ -62,6 +62,11 @@ module NoBrainer::Document::Types
62
62
  end
63
63
 
64
64
  def field(attr, options={})
65
+ if (type = options[:type]).is_a?(::Array)
66
+ raise ArgumentError, "Expected Array type to have single element, got #{types.inspect}" unless type.length == 1
67
+ options[:type] = NoBrainer::TypedArray.of(type.first)
68
+ end
69
+
65
70
  super
66
71
 
67
72
  type = options[:type]
@@ -108,7 +113,7 @@ module NoBrainer::Document::Types
108
113
  end
109
114
  end
110
115
 
111
- %w(binary boolean text geo enum).each do |type|
116
+ %w(array binary boolean text geo enum).each do |type|
112
117
  require File.join(File.dirname(__FILE__), 'types', type)
113
118
  const_set(type.camelize, NoBrainer.const_get(type.camelize))
114
119
  end
@@ -9,7 +9,7 @@ module NoBrainer::Document::Validation::NotNull
9
9
 
10
10
  class NotNullValidator < ActiveModel::EachValidator
11
11
  def validate_each(doc, attr, value)
12
- doc.errors.add(attr, :undefined, options) if value.nil?
12
+ doc.errors.add(attr, :undefined, **options) if value.nil?
13
13
  end
14
14
  end
15
15
  end
@@ -74,7 +74,7 @@ module NoBrainer::Document::Validation::Uniqueness
74
74
  criteria = self.model.unscoped.where(attr => value)
75
75
  criteria = apply_scopes(criteria, doc)
76
76
  criteria = exclude_doc(criteria, doc) if doc.persisted?
77
- doc.errors.add(attr, :taken, options.except(:scope).merge(:value => value)) unless criteria.empty?
77
+ doc.errors.add(attr, :taken, **options.except(:scope).merge(:value => value)) unless criteria.empty?
78
78
  rescue NoBrainer::Error::InvalidType
79
79
  # We can't run the uniqueness validator: where() won't accept bad types
80
80
  # and we have some values that don't have the right type.
@@ -7,7 +7,7 @@ module NoBrainer::Document
7
7
  autoload_and_include :Core, :TableConfig, :InjectionLayer, :Attributes, :Readonly,
8
8
  :Persistance, :Callbacks, :Validation, :Types, :Dirty, :PrimaryKey,
9
9
  :Association, :Serialization, :Criteria, :Polymorphic, :Index, :Aliases,
10
- :MissingAttributes, :LazyFetch, :AtomicOps, :VirtualAttributes
10
+ :MissingAttributes, :LazyFetch, :AtomicOps, :VirtualAttributes, :Store
11
11
 
12
12
  autoload :DynamicAttributes, :Timestamps
13
13
 
@@ -51,7 +51,7 @@ module NoBrainer::Error
51
51
  value = self.value
52
52
  mock = model.allocate
53
53
  mock.singleton_class.send(:define_method, :read_attribute_for_validation) { |_| value }
54
- mock.errors.add(attr_name, :invalid_type, error)
54
+ mock.errors.add(attr_name, :invalid_type, **error)
55
55
  mock.errors.full_messages.first
56
56
  end
57
57
  end
@@ -1,5 +1,5 @@
1
1
  module NoBrainer::SymbolDecoration
2
- NON_CHAINABLE_OPERATORS = %w(in eq gt ge gte lt le lte defined undefined near intersects include).map(&:to_sym)
2
+ NON_CHAINABLE_OPERATORS = %w(in eq gt ge gte lt le lte defined undefined near intersects include during).map(&:to_sym)
3
3
  CHAINABLE_OPERATORS = %w(not any all).map(&:to_sym)
4
4
  OPERATORS = CHAINABLE_OPERATORS + NON_CHAINABLE_OPERATORS
5
5
 
data/lib/nobrainer.rb CHANGED
@@ -37,6 +37,10 @@ module NoBrainer
37
37
  RUBY_PLATFORM == 'java'
38
38
  end
39
39
 
40
+ def rails4?
41
+ Gem.loaded_specs['activesupport'].version >= Gem::Version.new('4.0.0')
42
+ end
43
+
40
44
  def rails5?
41
45
  Gem.loaded_specs['activesupport'].version >= Gem::Version.new('5.0.0.beta')
42
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nobrainer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.34.1
4
+ version: 0.41.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Viennot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-25 00:00:00.000000000 Z
11
+ date: 2021-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 4.1.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: 4.1.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: activesupport
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -31,6 +37,9 @@ dependencies:
31
37
  - - ">="
32
38
  - !ruby/object:Gem::Version
33
39
  version: 4.1.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '8'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +47,9 @@ dependencies:
38
47
  - - ">="
39
48
  - !ruby/object:Gem::Version
40
49
  version: 4.1.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '8'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: middleware
43
55
  requirement: !ruby/object:Gem::Requirement
@@ -59,6 +71,9 @@ dependencies:
59
71
  - - ">="
60
72
  - !ruby/object:Gem::Version
61
73
  version: 2.3.0
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.5'
62
77
  type: :runtime
63
78
  prerelease: false
64
79
  version_requirements: !ruby/object:Gem::Requirement
@@ -66,6 +81,9 @@ dependencies:
66
81
  - - ">="
67
82
  - !ruby/object:Gem::Version
68
83
  version: 2.3.0
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: '2.5'
69
87
  - !ruby/object:Gem::Dependency
70
88
  name: symbol_decoration
71
89
  requirement: !ruby/object:Gem::Requirement
@@ -150,10 +168,12 @@ files:
150
168
  - lib/no_brainer/document/primary_key/generator.rb
151
169
  - lib/no_brainer/document/readonly.rb
152
170
  - lib/no_brainer/document/serialization.rb
171
+ - lib/no_brainer/document/store.rb
153
172
  - lib/no_brainer/document/table_config.rb
154
173
  - lib/no_brainer/document/table_config/synchronizer.rb
155
174
  - lib/no_brainer/document/timestamps.rb
156
175
  - lib/no_brainer/document/types.rb
176
+ - lib/no_brainer/document/types/array.rb
157
177
  - lib/no_brainer/document/types/binary.rb
158
178
  - lib/no_brainer/document/types/boolean.rb
159
179
  - lib/no_brainer/document/types/date.rb
@@ -221,7 +241,7 @@ files:
221
241
  - lib/rails/generators/templates/nobrainer.rb
222
242
  homepage: http://nobrainer.io
223
243
  licenses:
224
- - LGPLv3
244
+ - LGPL-3.0-only
225
245
  metadata: {}
226
246
  post_install_message:
227
247
  rdoc_options: []
@@ -238,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
258
  - !ruby/object:Gem::Version
239
259
  version: '0'
240
260
  requirements: []
241
- rubygems_version: 3.1.4
261
+ rubygems_version: 3.1.6
242
262
  signing_key:
243
263
  specification_version: 4
244
264
  summary: A Ruby ORM for RethinkDB