hyper-model 1.0.alpha1.2 → 1.0.alpha1.7
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
- data/.gitignore +4 -1
- data/.rspec +0 -1
- data/Gemfile +6 -5
- data/Rakefile +27 -3
- data/hyper-model.gemspec +11 -19
- data/lib/active_record_base.rb +105 -33
- data/lib/enumerable/pluck.rb +3 -2
- data/lib/hyper-model.rb +4 -1
- data/lib/hyper_model/version.rb +1 -1
- data/lib/hyper_react/input_tags.rb +2 -1
- data/lib/reactive_record/active_record/associations.rb +130 -34
- data/lib/reactive_record/active_record/base.rb +32 -0
- data/lib/reactive_record/active_record/class_methods.rb +124 -52
- data/lib/reactive_record/active_record/error.rb +2 -0
- data/lib/reactive_record/active_record/errors.rb +8 -4
- data/lib/reactive_record/active_record/instance_methods.rb +73 -5
- data/lib/reactive_record/active_record/public_columns_hash.rb +25 -26
- data/lib/reactive_record/active_record/reactive_record/backing_record_inspector.rb +22 -5
- data/lib/reactive_record/active_record/reactive_record/base.rb +50 -24
- data/lib/reactive_record/active_record/reactive_record/collection.rb +226 -68
- data/lib/reactive_record/active_record/reactive_record/dummy_polymorph.rb +22 -0
- data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +27 -15
- data/lib/reactive_record/active_record/reactive_record/getters.rb +33 -10
- data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +81 -51
- data/lib/reactive_record/active_record/reactive_record/lookup_tables.rb +5 -5
- data/lib/reactive_record/active_record/reactive_record/operations.rb +10 -3
- data/lib/reactive_record/active_record/reactive_record/scoped_collection.rb +3 -0
- data/lib/reactive_record/active_record/reactive_record/setters.rb +105 -68
- data/lib/reactive_record/active_record/reactive_record/while_loading.rb +249 -32
- data/lib/reactive_record/broadcast.rb +62 -25
- data/lib/reactive_record/interval.rb +3 -3
- data/lib/reactive_record/permissions.rb +14 -2
- data/lib/reactive_record/scope_description.rb +3 -2
- data/lib/reactive_record/server_data_cache.rb +99 -49
- data/polymorph-notes.md +143 -0
- data/spec_fails.txt +3 -0
- metadata +54 -153
- data/Gemfile.lock +0 -421
@@ -6,5 +6,37 @@ module ActiveRecord
|
|
6
6
|
|
7
7
|
scope :limit, ->() {}
|
8
8
|
scope :offset, ->() {}
|
9
|
+
|
10
|
+
finder_method :__hyperstack_internal_scoped_last
|
11
|
+
scope :__hyperstack_internal_scoped_last_n, ->(n) { last(n) }
|
12
|
+
|
13
|
+
def self.where(*args)
|
14
|
+
if args[0].is_a? Hash
|
15
|
+
# we can compute membership in the scope when the arg is a hash
|
16
|
+
__hyperstack_internal_where_hash_scope(args[0])
|
17
|
+
else
|
18
|
+
# otherwise the scope has to always be computed on the server
|
19
|
+
__hyperstack_internal_where_sql_scope(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
scope :__hyperstack_internal_where_hash_scope,
|
24
|
+
client: ->(attrs) { !attrs.detect { |k, v| self[k] != v } }
|
25
|
+
|
26
|
+
scope :__hyperstack_internal_where_sql_scope
|
27
|
+
|
28
|
+
ReactiveRecord::ScopeDescription.new(
|
29
|
+
self, :___hyperstack_internal_scoped_find_by,
|
30
|
+
client: ->(attrs) { !attrs.detect { |attr, value| attributes[attr] != value } }
|
31
|
+
)
|
32
|
+
|
33
|
+
def self.__hyperstack_internal_scoped_find_by(attrs)
|
34
|
+
collection = all.apply_scope(:___hyperstack_internal_scoped_find_by, attrs).observed
|
35
|
+
if !collection.collection
|
36
|
+
collection._find_by_initializer(self, attrs)
|
37
|
+
else
|
38
|
+
collection.first
|
39
|
+
end
|
40
|
+
end
|
9
41
|
end
|
10
42
|
end
|
@@ -1,11 +1,20 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
|
3
2
|
module ClassMethods
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
begin
|
4
|
+
# Opal 0.11 super did not work with new, but new was defined
|
5
|
+
alias _new_without_sti_type_cast new
|
6
|
+
def new(*args, &block)
|
7
|
+
_new_without_sti_type_cast(*args, &block).cast_to_current_sti_type
|
8
|
+
end
|
9
|
+
rescue NameError
|
10
|
+
def self.extended(base)
|
11
|
+
base.singleton_class.class_eval do
|
12
|
+
alias_method :_new_without_sti_type_cast, :new
|
13
|
+
define_method :new do |*args, &block|
|
14
|
+
_new_without_sti_type_cast(*args, &block).cast_to_current_sti_type
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
9
18
|
end
|
10
19
|
|
11
20
|
def base_class
|
@@ -51,14 +60,27 @@ module ActiveRecord
|
|
51
60
|
@model_name ||= ActiveModel::Name.new(self)
|
52
61
|
end
|
53
62
|
|
54
|
-
def
|
55
|
-
|
63
|
+
def __hyperstack_preprocess_attrs(attrs)
|
64
|
+
if inheritance_column && self < base_class && !attrs.key?(inheritance_column)
|
65
|
+
attrs = attrs.merge(inheritance_column => model_name.to_s)
|
66
|
+
end
|
67
|
+
dealiased_attrs = {}
|
68
|
+
attrs.each { |attr, value| dealiased_attrs[_dealias_attribute(attr)] = value }
|
69
|
+
dealiased_attrs
|
70
|
+
end
|
71
|
+
|
72
|
+
def find(*args)
|
73
|
+
args = args[0] if args[0].is_a? Array
|
74
|
+
return args.collect { |id| find(id) } if args.count > 1
|
75
|
+
find_by(primary_key => args[0])
|
56
76
|
end
|
57
77
|
|
58
|
-
def find_by(
|
59
|
-
|
60
|
-
|
61
|
-
|
78
|
+
def find_by(attrs = {})
|
79
|
+
attrs = __hyperstack_preprocess_attrs(attrs)
|
80
|
+
# r = ReactiveRecord::Base.find_locally(self, attrs, new_only: true)
|
81
|
+
# return r.ar_instance if r
|
82
|
+
(r = __hyperstack_internal_scoped_find_by(attrs)) || return
|
83
|
+
r.backing_record.sync_attributes(attrs).set_ar_instance!
|
62
84
|
end
|
63
85
|
|
64
86
|
def enum(*args)
|
@@ -162,7 +184,7 @@ module ActiveRecord
|
|
162
184
|
:full_table_name_prefix, :full_table_name_suffix, :reset_sequence_name, :sequence_name=, :next_sequence_value, :column_defaults, :content_columns,
|
163
185
|
:readonly_attributes, :attr_readonly, :create, :create!, :instantiate, :find, :type_caster, :arel_table, :find_by, :find_by!, :initialize_find_by_cache,
|
164
186
|
:generated_association_methods, :arel_engine, :arel_attribute, :predicate_builder, :collection_cache_key, :relation_delegate_class,
|
165
|
-
:initialize_relation_delegate_cache, :enum, :collecting_queries_for_explain, :exec_explain, :i18n_scope, :lookup_ancestors,
|
187
|
+
:initialize_relation_delegate_cache, :enum, :collecting_queries_for_explain, :exec_explain, :i18n_scope, :lookup_ancestors,
|
166
188
|
:references, :uniq, :maximum, :none, :exists?, :second, :limit, :order, :eager_load, :update, :delete_all, :destroy, :ids, :many?, :pluck, :third,
|
167
189
|
:delete, :fourth, :fifth, :forty_two, :second_to_last, :third_to_last, :preload, :sum, :take!, :first!, :last!, :second!, :offset, :select, :fourth!,
|
168
190
|
:third!, :third_to_last!, :fifth!, :where, :first_or_create, :second_to_last!, :forty_two!, :first, :having, :any?, :one?, :none?, :find_or_create_by,
|
@@ -175,8 +197,11 @@ module ActiveRecord
|
|
175
197
|
]
|
176
198
|
|
177
199
|
def method_missing(name, *args, &block)
|
178
|
-
if
|
179
|
-
|
200
|
+
if name == 'human_attribute_name'
|
201
|
+
opts = args[1] || {}
|
202
|
+
opts[:default] || args[0]
|
203
|
+
elsif args.count == 1 && name.start_with?("find_by_") && !block
|
204
|
+
find_by(name.sub(/^find_by_/, '') => args[0])
|
180
205
|
elsif [].respond_to?(name)
|
181
206
|
all.send(name, *args, &block)
|
182
207
|
elsif name.end_with?('!')
|
@@ -193,16 +218,6 @@ module ActiveRecord
|
|
193
218
|
# Any method ending with ! just means apply the method after forcing a reload
|
194
219
|
# from the DB.
|
195
220
|
|
196
|
-
# alias pre_synchromesh_method_missing method_missing
|
197
|
-
#
|
198
|
-
# def method_missing(name, *args, &block)
|
199
|
-
# return all.send(name, *args, &block) if [].respond_to?(name)
|
200
|
-
# if name.end_with?('!')
|
201
|
-
# return send(name.chop, *args, &block).send(:reload_from_db) rescue nil
|
202
|
-
# end
|
203
|
-
# pre_synchromesh_method_missing(name, *args, &block)
|
204
|
-
# end
|
205
|
-
|
206
221
|
def create(*args, &block)
|
207
222
|
new(*args).save(&block)
|
208
223
|
end
|
@@ -213,9 +228,6 @@ module ActiveRecord
|
|
213
228
|
singleton_class.send(:define_method, name) do |*vargs|
|
214
229
|
all.build_child_scope(scope_description, *name, *vargs)
|
215
230
|
end
|
216
|
-
# singleton_class.send(:define_method, "#{name}=") do |_collection|
|
217
|
-
# raise 'NO LONGER IMPLEMENTED - DOESNT PLAY WELL WITH SYNCHROMESH'
|
218
|
-
# end
|
219
231
|
end
|
220
232
|
|
221
233
|
def default_scope(*args, &block)
|
@@ -249,10 +261,6 @@ module ActiveRecord
|
|
249
261
|
end
|
250
262
|
end
|
251
263
|
|
252
|
-
# def all=(_collection)
|
253
|
-
# raise "NO LONGER IMPLEMENTED DOESNT PLAY WELL WITH SYNCHROMESH"
|
254
|
-
# end
|
255
|
-
|
256
264
|
def unscoped
|
257
265
|
ReactiveRecord::Base.unscoped[self] ||=
|
258
266
|
ReactiveRecord::Collection
|
@@ -264,7 +272,8 @@ module ActiveRecord
|
|
264
272
|
ReactiveRecord::ScopeDescription.new(self, "_#{name}", {})
|
265
273
|
[name, "#{name}!"].each do |method|
|
266
274
|
singleton_class.send(:define_method, method) do |*vargs|
|
267
|
-
all.apply_scope("_#{method}", *vargs)
|
275
|
+
collection = all.apply_scope("_#{method}", *vargs)
|
276
|
+
collection.first
|
268
277
|
end
|
269
278
|
end
|
270
279
|
end
|
@@ -298,24 +307,34 @@ module ActiveRecord
|
|
298
307
|
assoc = Associations::AssociationReflection.new(self, macro, name, opts)
|
299
308
|
if macro == :has_many
|
300
309
|
define_method(name) { @backing_record.get_has_many(assoc, nil) }
|
301
|
-
define_method("#{name}
|
310
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_has_many(assoc, val) }
|
302
311
|
else
|
303
312
|
define_method(name) { @backing_record.get_belongs_to(assoc, nil) }
|
304
|
-
define_method("#{name}
|
313
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_belongs_to(assoc, val) }
|
305
314
|
end
|
315
|
+
alias_method "#{name}=", "_hyperstack_internal_setter_#{name}"
|
306
316
|
assoc
|
307
317
|
end
|
308
318
|
end
|
309
319
|
|
320
|
+
def table_name
|
321
|
+
@table_name || name.downcase.pluralize
|
322
|
+
end
|
323
|
+
|
324
|
+
def table_name=(name)
|
325
|
+
@table_name = name
|
326
|
+
end
|
327
|
+
|
310
328
|
def composed_of(name, opts = {})
|
311
329
|
reflection = Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
|
312
330
|
if reflection.klass < ActiveRecord::Base
|
313
331
|
define_method(name) { @backing_record.get_ar_aggregate(reflection, nil) }
|
314
|
-
define_method("#{name}
|
332
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_ar_aggregate(reflection, val) }
|
315
333
|
else
|
316
334
|
define_method(name) { @backing_record.get_non_ar_aggregate(name, nil) }
|
317
|
-
define_method("#{name}
|
335
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_non_ar_aggregate(reflection, val) }
|
318
336
|
end
|
337
|
+
alias_method "#{name}=", "_hyperstack_internal_setter_#{name}"
|
319
338
|
end
|
320
339
|
|
321
340
|
def column_names
|
@@ -340,16 +359,31 @@ module ActiveRecord
|
|
340
359
|
vector = args.count.zero? ? name : [[name] + args]
|
341
360
|
@backing_record.get_server_method(vector, true)
|
342
361
|
end
|
362
|
+
define_method("_hyperstack_internal_setter_#{name}") do |val|
|
363
|
+
backing_record.set_attr_value(name, val)
|
364
|
+
end
|
343
365
|
end
|
344
366
|
|
367
|
+
# define all the methods for each column. To allow overriding the methods they will NOT
|
368
|
+
# be defined if already defined (i.e. by the model) See the instance_methods module for how
|
369
|
+
# super calls are handled in this case. The _hyperstack_internal_setter_... methods
|
370
|
+
# are used by the load_from_json method when bringing in data from the server, and so therefore
|
371
|
+
# does not want to be overriden.
|
372
|
+
|
345
373
|
def define_attribute_methods
|
346
374
|
columns_hash.each do |name, column_hash|
|
347
|
-
next if name ==
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
375
|
+
next if name == :id
|
376
|
+
# only add serialized key if its serialized. This just makes testing a bit
|
377
|
+
# easier by keeping the columns_hash the same if there are no seralized strings
|
378
|
+
# see rspec ./spec/batch1/column_types/column_type_spec.rb:100
|
379
|
+
column_hash[:serialized?] = true if ReactiveRecord::Base.serialized?[self][name]
|
380
|
+
|
381
|
+
define_method(name) { @backing_record.get_attr_value(name, nil) } unless method_defined?(name)
|
382
|
+
define_method("#{name}!") { @backing_record.get_attr_value(name, true) } unless method_defined?("#{name}!")
|
383
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_attr_value(name, val) }
|
384
|
+
alias_method "#{name}=", "_hyperstack_internal_setter_#{name}" unless method_defined?("#{name}=")
|
385
|
+
define_method("#{name}_changed?") { @backing_record.changed?(name) } unless method_defined?("#{name}_changed?")
|
386
|
+
define_method("#{name}?") { @backing_record.get_attr_value(name, nil).present? } unless method_defined?("#{name}?")
|
353
387
|
end
|
354
388
|
self.inheritance_column = nil if inheritance_column && !columns_hash.key?(inheritance_column)
|
355
389
|
end
|
@@ -370,29 +404,67 @@ module ActiveRecord
|
|
370
404
|
# TODO: changed values as changes while just updating the synced values.
|
371
405
|
target =
|
372
406
|
if param[primary_key]
|
373
|
-
find(param[primary_key])
|
407
|
+
ReactiveRecord::Base.find(self, primary_key => param[primary_key]).tap do |r|
|
408
|
+
r.backing_record.loaded_id = param[primary_key]
|
409
|
+
end
|
374
410
|
else
|
375
411
|
new
|
376
412
|
end
|
377
413
|
|
378
414
|
associations = reflect_on_all_associations
|
379
415
|
|
416
|
+
already_processed_keys = Set.new
|
417
|
+
|
380
418
|
param = param.collect do |key, value|
|
381
|
-
|
382
|
-
|
419
|
+
next if already_processed_keys.include? key
|
420
|
+
|
421
|
+
model_name = model_id = nil
|
422
|
+
|
423
|
+
# polymorphic association is where the belongs_to side holds the
|
424
|
+
# id, and the type of the model the id points to
|
425
|
+
|
426
|
+
# belongs_to :duplicate_of, class_name: 'Report', required: false
|
427
|
+
# has_many :duplicates, class_name: 'Report', foreign_key: 'duplicate_of_id'
|
428
|
+
|
429
|
+
assoc = associations.detect do |poly_assoc|
|
430
|
+
if key == poly_assoc.polymorphic_type_attribute
|
431
|
+
model_name = value
|
432
|
+
already_processed_keys << poly_assoc.association_foreign_key
|
433
|
+
elsif key == poly_assoc.association_foreign_key && (poly_assoc.polymorphic_type_attribute || poly_assoc.macro == :belongs_to)
|
434
|
+
model_id = value
|
435
|
+
already_processed_keys << poly_assoc.polymorphic_type_attribute
|
436
|
+
end
|
383
437
|
end
|
384
438
|
|
385
439
|
if assoc
|
386
|
-
if value
|
387
|
-
[assoc.attribute, { id: [value] }]
|
388
|
-
else
|
440
|
+
if !value
|
389
441
|
[assoc.attribute, [nil]]
|
442
|
+
elsif assoc.polymorphic?
|
443
|
+
model_id ||= param.detect { |k, *| k == assoc.association_foreign_key }&.last
|
444
|
+
model_id ||= target.send(assoc.attribute)&.id
|
445
|
+
if model_id.nil?
|
446
|
+
raise "Error in #{self.name}._react_param_conversion. \n"\
|
447
|
+
"Could not determine the id of #{assoc.attribute} of #{target.inspect}.\n"\
|
448
|
+
"It was not provided in the conversion data, "\
|
449
|
+
"and it is unknown on the client"
|
450
|
+
end
|
451
|
+
model_name ||= param.detect { |k, *| k == assoc.polymorphic_type_attribute }&.last
|
452
|
+
model_name ||= target.send(assoc.polymorphic_type_attribute)
|
453
|
+
unless Object.const_defined?(model_name)
|
454
|
+
raise "Error in #{self.name}._react_param_conversion. \n"\
|
455
|
+
"Could not determine the type of #{assoc.attribute} of #{target.inspect}.\n"\
|
456
|
+
"It was not provided in the conversion data, "\
|
457
|
+
"and it is unknown on the client"
|
458
|
+
end
|
459
|
+
|
460
|
+
[assoc.attribute, { id: [model_id], model_name: [model_name] }]
|
461
|
+
else
|
462
|
+
[assoc.attribute, { id: [value]}]
|
390
463
|
end
|
391
464
|
else
|
392
|
-
[key, [value]]
|
465
|
+
[*key, [value]]
|
393
466
|
end
|
394
|
-
end
|
395
|
-
# TODO: verify wrapping with load_data was added so broadcasting works in 1.0.0.lap28
|
467
|
+
end.compact
|
396
468
|
ReactiveRecord::Base.load_data do
|
397
469
|
ReactiveRecord::ServerDataCache.load_from_json(Hash[param], target)
|
398
470
|
end
|
@@ -89,7 +89,7 @@ module ActiveModel
|
|
89
89
|
# person.errors.values # => [["cannot be nil", "must be specified"]]
|
90
90
|
def values
|
91
91
|
messages.select do |key, value|
|
92
|
-
!value
|
92
|
+
!value&.empty?
|
93
93
|
end.values
|
94
94
|
end
|
95
95
|
|
@@ -105,9 +105,9 @@ module ActiveModel
|
|
105
105
|
attr_name =
|
106
106
|
attribute.to_s.tr('.', '_').tr('_', ' ').gsub(/_id$/, '').capitalize
|
107
107
|
# attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
|
108
|
-
|
108
|
+
if @base.class.respond_to?(:human_attribute_name)
|
109
109
|
attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
|
110
|
-
|
110
|
+
end
|
111
111
|
# I18n.t(:"errors.format",
|
112
112
|
# default: "%{attribute} %{message}",
|
113
113
|
# attribute: attr_name,
|
@@ -219,8 +219,12 @@ module ActiveModel
|
|
219
219
|
# person.errors.clear
|
220
220
|
# person.errors.full_messages # => []
|
221
221
|
def clear
|
222
|
+
non_reactive_clear.tap { reactive_empty! true }
|
223
|
+
end
|
224
|
+
|
225
|
+
def non_reactive_clear
|
222
226
|
messages.clear
|
223
|
-
details.clear
|
227
|
+
details.clear
|
224
228
|
end
|
225
229
|
|
226
230
|
# Merges the errors from <tt>other</tt>.
|
@@ -1,5 +1,59 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module InstanceMethods
|
3
|
+
|
4
|
+
# if methods are missing, then they must be a column, which we look up
|
5
|
+
# in the columns_hash.
|
6
|
+
|
7
|
+
# For effeciency all attributes will by default have all the methods defined,
|
8
|
+
# when the class is loaded. See define_attribute_methods class method.
|
9
|
+
# However a model may override the attribute methods definition, but then call
|
10
|
+
# super. Which will result in the method missing call.
|
11
|
+
|
12
|
+
# When loading data from the server we do NOT want to call overridden methods
|
13
|
+
# so we also define a _hyperstack_internal_setter_... method for each attribute
|
14
|
+
# as well as for belongs_to relationships, server_methods, and the special
|
15
|
+
# type and model_name methods. See the ClassMethods module for details.
|
16
|
+
|
17
|
+
# meanwhile in Opal 1.0 there is currently an issue where the name of the method
|
18
|
+
# does not get passed to method_missing from super.
|
19
|
+
# https://github.com/opal/opal/issues/2165
|
20
|
+
# So the following hack works around that issue until its fixed.
|
21
|
+
|
22
|
+
%x{
|
23
|
+
Opal.orig_find_super_dispatcher = Opal.find_super_dispatcher
|
24
|
+
Opal.find_super_dispatcher = function(obj, mid, current_func, defcheck, allow_stubs) {
|
25
|
+
Opal.__name_of_super = mid;
|
26
|
+
return Opal.orig_find_super_dispatcher(obj, mid, current_func, defcheck, allow_stubs)
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
def method_missing(missing, *args, &block)
|
31
|
+
missing ||= `Opal.__name_of_super`
|
32
|
+
column = self.class.columns_hash.detect { |name, *| missing =~ /^#{name}/ }
|
33
|
+
if column
|
34
|
+
name = column[0]
|
35
|
+
case missing
|
36
|
+
when /\!\z/ then @backing_record.get_attr_value(name, true)
|
37
|
+
when /\=\z/ then @backing_record.set_attr_value(name, *args)
|
38
|
+
when /\_changed\?\z/ then @backing_record.changed?(name)
|
39
|
+
when /\?/ then @backing_record.get_attr_value(name, nil).present?
|
40
|
+
else @backing_record.get_attr_value(name, nil)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# the system assumes that there is "virtual" model_name and type attribute so
|
48
|
+
# we define the internal setter here. If the user defines some other attributes
|
49
|
+
# or uses these names no harm is done since the exact same method would have been
|
50
|
+
# defined by the define_attribute_methods class method anyway.
|
51
|
+
%i[model_name type].each do |attr|
|
52
|
+
define_method("_hyperstack_internal_setter_#{attr}") do |val|
|
53
|
+
@backing_record.set_attr_value(:model_name, val)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
3
57
|
def inspect
|
4
58
|
"<#{model_name}:#{ReactiveRecord::Operations::Base::FORMAT % to_key} "\
|
5
59
|
"(#{ReactiveRecord::Operations::Base::FORMAT % object_id}) "\
|
@@ -38,7 +92,7 @@ module ActiveRecord
|
|
38
92
|
end
|
39
93
|
self.class.load_data do
|
40
94
|
h.each do |attribute, value|
|
41
|
-
next if attribute ==
|
95
|
+
next if attribute == :id
|
42
96
|
@ar_instance[attribute] = value
|
43
97
|
changed_attributes << attribute
|
44
98
|
end
|
@@ -72,8 +126,8 @@ module ActiveRecord
|
|
72
126
|
@backing_record.revert
|
73
127
|
end
|
74
128
|
|
75
|
-
def changed?
|
76
|
-
@backing_record.changed?
|
129
|
+
def changed?(attr = nil)
|
130
|
+
@backing_record.changed?(*attr)
|
77
131
|
end
|
78
132
|
|
79
133
|
def dup
|
@@ -81,7 +135,11 @@ module ActiveRecord
|
|
81
135
|
end
|
82
136
|
|
83
137
|
def ==(ar_instance)
|
84
|
-
@backing_record == ar_instance.instance_eval { @backing_record }
|
138
|
+
return true if @backing_record == ar_instance.instance_eval { @backing_record }
|
139
|
+
return false unless ar_instance.is_a?(ActiveRecord::Base)
|
140
|
+
return false if ar_instance.new_record?
|
141
|
+
return false unless self.class.base_class == ar_instance.class.base_class
|
142
|
+
id == ar_instance.id
|
85
143
|
end
|
86
144
|
|
87
145
|
def [](attr)
|
@@ -104,6 +162,14 @@ module ActiveRecord
|
|
104
162
|
# end
|
105
163
|
end
|
106
164
|
|
165
|
+
def increment!(attr)
|
166
|
+
load(attr).then { |current_value| update(attr => current_value + 1) }
|
167
|
+
end
|
168
|
+
|
169
|
+
def decrement!(attr)
|
170
|
+
load(attr).then { |current_value| update(attr => current_value - 1) }
|
171
|
+
end
|
172
|
+
|
107
173
|
def load(*attributes, &block)
|
108
174
|
first_time = true
|
109
175
|
ReactiveRecord.load do
|
@@ -144,10 +210,12 @@ module ActiveRecord
|
|
144
210
|
@backing_record.destroyed
|
145
211
|
end
|
146
212
|
|
147
|
-
def
|
213
|
+
def new_record?
|
148
214
|
@backing_record.new?
|
149
215
|
end
|
150
216
|
|
217
|
+
alias new? new_record?
|
218
|
+
|
151
219
|
def errors
|
152
220
|
Hyperstack::Internal::State::Variable.get(@backing_record, @backing_record)
|
153
221
|
@backing_record.errors
|