hyper-model 1.0.alpha1.5 → 1.0.alpha1.6
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/.rspec +0 -1
- data/Gemfile +6 -5
- data/Rakefile +1 -1
- data/hyper-model.gemspec +11 -19
- data/lib/active_record_base.rb +58 -12
- data/lib/hyper-model.rb +3 -1
- data/lib/hyper_model/version.rb +1 -1
- data/lib/reactive_record/active_record/associations.rb +8 -3
- data/lib/reactive_record/active_record/base.rb +1 -1
- data/lib/reactive_record/active_record/class_methods.rb +54 -32
- data/lib/reactive_record/active_record/instance_methods.rb +48 -3
- data/lib/reactive_record/active_record/reactive_record/base.rb +2 -2
- data/lib/reactive_record/active_record/reactive_record/collection.rb +77 -27
- data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +26 -15
- data/lib/reactive_record/active_record/reactive_record/getters.rb +4 -2
- data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +17 -23
- data/lib/reactive_record/active_record/reactive_record/operations.rb +7 -1
- data/lib/reactive_record/active_record/reactive_record/setters.rb +2 -3
- data/lib/reactive_record/active_record/reactive_record/while_loading.rb +22 -1
- data/lib/reactive_record/broadcast.rb +21 -10
- data/lib/reactive_record/server_data_cache.rb +56 -44
- metadata +44 -150
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b2f63052beefadb742e008e12976afe889105a0cdbd864ea49902654eb82be51
|
|
4
|
+
data.tar.gz: 2bdf35fb8b4ccd7fd00144be9ba52d8a133797e47825b91cf6acae8dc0673043
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e7481f8e04d3d464507d7c25c20b3dc55167dd6b8cb368f28113e9f52b4ba95815611b8f4fe740d207860f1bc60cdb4ddcdafb996d83ddf2d51afb8cc397fb5
|
|
7
|
+
data.tar.gz: e0e5fb04e304496c3d0ef8353a9ed0bd36a303257e3f062d9ed61e75b4af8d1ded8ed18defd37e7e44dd79b618b221d129287a39d9e331bb20b9cc648c668124
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
|
-
#gem "opal-jquery", git: "https://github.com/opal/opal-jquery.git", branch: "master"
|
|
3
|
-
# hyper-model is still using an ancient inlined version of hyper-spec
|
|
4
|
-
#gem 'hyper-spec', path: '../hyper-spec'
|
|
5
|
-
gem 'hyperstack-config', path: '../hyperstack-config'
|
|
6
2
|
gem 'hyper-state', path: '../hyper-state'
|
|
7
3
|
gem 'hyper-component', path: '../hyper-component'
|
|
8
4
|
gem 'hyper-operation', path: '../hyper-operation'
|
|
9
|
-
|
|
5
|
+
gem 'hyper-spec', path: '../hyper-spec'
|
|
6
|
+
gem 'hyper-trace', path: '../hyper-trace'
|
|
7
|
+
gem 'hyperstack-config', path: '../hyperstack-config'
|
|
8
|
+
unless ENV['OPAL_VERSION']&.match("0.11")
|
|
9
|
+
gem 'opal-browser', git: 'https://github.com/opal/opal-browser'
|
|
10
|
+
end
|
|
10
11
|
gemspec
|
data/Rakefile
CHANGED
|
@@ -32,7 +32,7 @@ end
|
|
|
32
32
|
|
|
33
33
|
namespace :spec do
|
|
34
34
|
task :prepare do
|
|
35
|
-
sh %(cd spec/test_app; bundle exec rails db:setup)
|
|
35
|
+
sh %(cd spec/test_app; rm db/schema.rb; RAILS_ENV=test bundle exec rails db:setup; RAILS_ENV=test bundle exec rails db:migrate)
|
|
36
36
|
end
|
|
37
37
|
(1..7).each do |batch|
|
|
38
38
|
RSpec::Core::RakeTask.new(:"batch#{batch}") do |t|
|
data/hyper-model.gemspec
CHANGED
|
@@ -27,31 +27,24 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
|
|
28
28
|
spec.add_dependency 'activemodel'
|
|
29
29
|
spec.add_dependency 'activerecord', '>= 4.0.0'
|
|
30
|
-
spec.add_dependency 'hyper-component', HyperModel::VERSION
|
|
31
30
|
spec.add_dependency 'hyper-operation', HyperModel::VERSION
|
|
32
|
-
|
|
33
|
-
spec.add_development_dependency '
|
|
34
|
-
spec.add_development_dependency 'chromedriver-helper', '1.2.0'
|
|
35
|
-
spec.add_development_dependency 'libv8'
|
|
36
|
-
spec.add_development_dependency 'mini_racer', '~> 0.2.4'
|
|
37
|
-
spec.add_development_dependency 'selenium-webdriver'
|
|
31
|
+
|
|
32
|
+
spec.add_development_dependency 'bundler'
|
|
38
33
|
spec.add_development_dependency 'database_cleaner'
|
|
39
34
|
spec.add_development_dependency 'factory_bot_rails'
|
|
40
|
-
|
|
41
|
-
spec.add_development_dependency '
|
|
42
|
-
spec.add_development_dependency '
|
|
43
|
-
spec.add_development_dependency '
|
|
44
|
-
spec.add_development_dependency 'opal-rails', '
|
|
45
|
-
spec.add_development_dependency 'parser'
|
|
46
|
-
spec.add_development_dependency 'pry'
|
|
35
|
+
spec.add_development_dependency 'hyper-spec', HyperModel::VERSION
|
|
36
|
+
spec.add_development_dependency 'hyper-trace', HyperModel::VERSION
|
|
37
|
+
spec.add_development_dependency 'mini_racer'
|
|
38
|
+
spec.add_development_dependency 'pg'
|
|
39
|
+
spec.add_development_dependency 'opal-rails', '>= 0.9.4', '< 2.0'
|
|
47
40
|
spec.add_development_dependency 'pry-rescue'
|
|
41
|
+
spec.add_development_dependency 'pry-stack_explorer'
|
|
48
42
|
spec.add_development_dependency 'puma'
|
|
49
43
|
spec.add_development_dependency 'pusher'
|
|
50
44
|
spec.add_development_dependency 'pusher-fake'
|
|
51
|
-
spec.add_development_dependency 'rails', '>=
|
|
45
|
+
spec.add_development_dependency 'rails', ENV['RAILS_VERSION'] || '>= 5.0.0', '< 7.0'
|
|
52
46
|
spec.add_development_dependency 'rake'
|
|
53
47
|
spec.add_development_dependency 'react-rails', '>= 2.4.0', '< 2.5.0'
|
|
54
|
-
spec.add_development_dependency 'reactrb-rails-generator'
|
|
55
48
|
spec.add_development_dependency 'rspec-collection_matchers'
|
|
56
49
|
spec.add_development_dependency 'rspec-expectations'
|
|
57
50
|
spec.add_development_dependency 'rspec-its'
|
|
@@ -62,8 +55,7 @@ Gem::Specification.new do |spec|
|
|
|
62
55
|
spec.add_development_dependency 'rubocop', '~> 0.51.0'
|
|
63
56
|
spec.add_development_dependency 'shoulda'
|
|
64
57
|
spec.add_development_dependency 'shoulda-matchers'
|
|
65
|
-
spec.add_development_dependency 'spring-commands-rspec'
|
|
66
|
-
spec.add_development_dependency 'sqlite3', '~> 1.
|
|
58
|
+
spec.add_development_dependency 'spring-commands-rspec', '~> 1.0.4'
|
|
59
|
+
spec.add_development_dependency 'sqlite3', '~> 1.4.2' # see https://github.com/rails/rails/issues/35153, '~> 1.3.6'
|
|
67
60
|
spec.add_development_dependency 'timecop', '~> 0.8.1'
|
|
68
|
-
spec.add_development_dependency 'unparser'
|
|
69
61
|
end
|
data/lib/active_record_base.rb
CHANGED
|
@@ -5,17 +5,46 @@ module ActiveRecord
|
|
|
5
5
|
# processes these arguments, and the will always leave the true server side scoping
|
|
6
6
|
# proc in the `:server` opts. This method is common to client and server.
|
|
7
7
|
class Base
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
args[0]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
class << self
|
|
9
|
+
def _synchromesh_scope_args_check(args)
|
|
10
|
+
opts = if args.count == 2 && args[1].is_a?(Hash)
|
|
11
|
+
args[1].merge(server: args[0])
|
|
12
|
+
elsif args[0].is_a? Hash
|
|
13
|
+
args[0]
|
|
14
|
+
else
|
|
15
|
+
{ server: args[0] }
|
|
16
|
+
end
|
|
17
|
+
return opts if opts && opts[:server].respond_to?(:call)
|
|
18
|
+
raise 'must provide either a proc as the first arg or by the '\
|
|
19
|
+
'`:server` option to scope and default_scope methods'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
alias pre_hyperstack_has_and_belongs_to_many has_and_belongs_to_many unless RUBY_ENGINE == 'opal'
|
|
23
|
+
|
|
24
|
+
def has_and_belongs_to_many(other, opts = {}, &block)
|
|
25
|
+
join_table_name = [other.to_s, table_name].sort.join('_')
|
|
26
|
+
join_model_name = "HyperstackInternalHabtm#{join_table_name.singularize.camelize}"
|
|
27
|
+
join_model =
|
|
28
|
+
if Object.const_defined? join_model_name
|
|
29
|
+
Object.const_get(join_model_name)
|
|
30
|
+
else
|
|
31
|
+
Object.const_set(join_model_name, Class.new(ActiveRecord::Base))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
join_model.class_eval { belongs_to other.to_s.singularize.to_sym }
|
|
35
|
+
|
|
36
|
+
has_many join_model_name.underscore.pluralize.to_sym
|
|
37
|
+
|
|
38
|
+
if RUBY_ENGINE == 'opal'
|
|
39
|
+
Object.const_set("HABTM_#{other.to_s.camelize}", join_model)
|
|
40
|
+
join_model.inheritance_column = nil
|
|
41
|
+
has_many other, through: join_model_name.underscore.pluralize.to_sym
|
|
42
|
+
else
|
|
43
|
+
join_model.table_name = join_table_name
|
|
44
|
+
join_model.belongs_to other
|
|
45
|
+
pre_hyperstack_has_and_belongs_to_many(other, opts, &block)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
19
48
|
end
|
|
20
49
|
end
|
|
21
50
|
if RUBY_ENGINE != 'opal'
|
|
@@ -270,6 +299,12 @@ module ActiveRecord
|
|
|
270
299
|
Hyperstack::InternalPolicy.raise_operation_access_violation(:scoped_denied, "#{self.class} regulation denies scope access. Called from #{caller_locations(1)}")
|
|
271
300
|
end
|
|
272
301
|
|
|
302
|
+
unless method_defined? :saved_changes # for backwards compatibility to Rails < 5.1.7
|
|
303
|
+
def saved_changes
|
|
304
|
+
previous_changes
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
273
308
|
# call do_not_synchronize to block synchronization of a model
|
|
274
309
|
|
|
275
310
|
def self.do_not_synchronize
|
|
@@ -286,17 +321,28 @@ module ActiveRecord
|
|
|
286
321
|
self.class.do_not_synchronize?
|
|
287
322
|
end
|
|
288
323
|
|
|
324
|
+
before_create :synchromesh_mark_update_time
|
|
325
|
+
before_update :synchromesh_mark_update_time
|
|
326
|
+
before_destroy :synchromesh_mark_update_time
|
|
327
|
+
|
|
328
|
+
attr_reader :__synchromesh_update_time
|
|
329
|
+
|
|
330
|
+
def synchromesh_mark_update_time
|
|
331
|
+
@__synchromesh_update_time = Time.now.to_f
|
|
332
|
+
end
|
|
333
|
+
|
|
289
334
|
after_commit :synchromesh_after_create, on: [:create]
|
|
290
335
|
after_commit :synchromesh_after_change, on: [:update]
|
|
291
336
|
after_commit :synchromesh_after_destroy, on: [:destroy]
|
|
292
337
|
|
|
293
338
|
def synchromesh_after_create
|
|
339
|
+
puts "#{self}.synchromesh_after_create: #{do_not_synchronize?} channels: #{Hyperstack::Connection.active}" if Hyperstack::Connection.show_diagnostics
|
|
294
340
|
return if do_not_synchronize?
|
|
295
341
|
ReactiveRecord::Broadcast.after_commit :create, self
|
|
296
342
|
end
|
|
297
343
|
|
|
298
344
|
def synchromesh_after_change
|
|
299
|
-
return if do_not_synchronize? ||
|
|
345
|
+
return if do_not_synchronize? || saved_changes.empty?
|
|
300
346
|
ReactiveRecord::Broadcast.after_commit :change, self
|
|
301
347
|
end
|
|
302
348
|
|
data/lib/hyper-model.rb
CHANGED
data/lib/hyper_model/version.rb
CHANGED
|
@@ -3,7 +3,7 @@ module ActiveRecord
|
|
|
3
3
|
class Base
|
|
4
4
|
|
|
5
5
|
def self.reflect_on_all_associations
|
|
6
|
-
|
|
6
|
+
@associations ||= superclass.instance_eval { @associations&.dup || [] }
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def self.reflect_on_association(attr)
|
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def self.reflect_on_association_by_foreign_key(key)
|
|
14
|
-
reflection_finder { |assoc| assoc.association_foreign_key == key }
|
|
14
|
+
reflection_finder { |assoc| assoc.association_foreign_key == key && assoc.macro != :has_many }
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def self.reflection_finder(&block)
|
|
@@ -32,7 +32,7 @@ module ActiveRecord
|
|
|
32
32
|
module Associations
|
|
33
33
|
|
|
34
34
|
class AssociationReflection
|
|
35
|
-
|
|
35
|
+
attr_reader :klass_name
|
|
36
36
|
attr_reader :association_foreign_key
|
|
37
37
|
attr_reader :attribute
|
|
38
38
|
attr_reader :macro
|
|
@@ -79,6 +79,10 @@ module ActiveRecord
|
|
|
79
79
|
@macro != :has_many
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
+
def habtm?
|
|
83
|
+
through_association&.klass_name =~ /^HyperstackInternalHabtm/
|
|
84
|
+
end
|
|
85
|
+
|
|
82
86
|
def through_association
|
|
83
87
|
return unless @options[:through]
|
|
84
88
|
@through_association ||= @owner_class.reflect_on_all_associations.detect do |association|
|
|
@@ -161,6 +165,7 @@ module ActiveRecord
|
|
|
161
165
|
def find_inverse(model) # private
|
|
162
166
|
the_klass = klass(model)
|
|
163
167
|
the_klass.reflect_on_all_associations.each do |association|
|
|
168
|
+
next if association == self
|
|
164
169
|
next if association.association_foreign_key != @association_foreign_key
|
|
165
170
|
next if association.attribute == attribute
|
|
166
171
|
return association if association.polymorphic? || association.klass == owner_class
|
|
@@ -16,7 +16,7 @@ module ActiveRecord
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
def self.__hyperstack_internal_scoped_find_by(attrs)
|
|
19
|
-
collection = all.apply_scope(:___hyperstack_internal_scoped_find_by, attrs)
|
|
19
|
+
collection = all.apply_scope(:___hyperstack_internal_scoped_find_by, attrs).observed
|
|
20
20
|
if !collection.collection
|
|
21
21
|
collection._find_by_initializer(self, attrs)
|
|
22
22
|
else
|
|
@@ -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
|
|
@@ -57,10 +66,13 @@ module ActiveRecord
|
|
|
57
66
|
end
|
|
58
67
|
dealiased_attrs = {}
|
|
59
68
|
attrs.each { |attr, value| dealiased_attrs[_dealias_attribute(attr)] = value }
|
|
69
|
+
dealiased_attrs
|
|
60
70
|
end
|
|
61
71
|
|
|
62
|
-
def find(
|
|
63
|
-
|
|
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])
|
|
64
76
|
end
|
|
65
77
|
|
|
66
78
|
def find_by(attrs = {})
|
|
@@ -295,24 +307,34 @@ module ActiveRecord
|
|
|
295
307
|
assoc = Associations::AssociationReflection.new(self, macro, name, opts)
|
|
296
308
|
if macro == :has_many
|
|
297
309
|
define_method(name) { @backing_record.get_has_many(assoc, nil) }
|
|
298
|
-
define_method("#{name}
|
|
310
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_has_many(assoc, val) }
|
|
299
311
|
else
|
|
300
312
|
define_method(name) { @backing_record.get_belongs_to(assoc, nil) }
|
|
301
|
-
define_method("#{name}
|
|
313
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_belongs_to(assoc, val) }
|
|
302
314
|
end
|
|
315
|
+
alias_method "#{name}=", "_hyperstack_internal_setter_#{name}"
|
|
303
316
|
assoc
|
|
304
317
|
end
|
|
305
318
|
end
|
|
306
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
|
+
|
|
307
328
|
def composed_of(name, opts = {})
|
|
308
329
|
reflection = Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
|
|
309
330
|
if reflection.klass < ActiveRecord::Base
|
|
310
331
|
define_method(name) { @backing_record.get_ar_aggregate(reflection, nil) }
|
|
311
|
-
define_method("#{name}
|
|
332
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_ar_aggregate(reflection, val) }
|
|
312
333
|
else
|
|
313
334
|
define_method(name) { @backing_record.get_non_ar_aggregate(name, nil) }
|
|
314
|
-
define_method("#{name}
|
|
335
|
+
define_method("_hyperstack_internal_setter_#{name}") { |val| @backing_record.set_non_ar_aggregate(reflection, val) }
|
|
315
336
|
end
|
|
337
|
+
alias_method "#{name}=", "_hyperstack_internal_setter_#{name}"
|
|
316
338
|
end
|
|
317
339
|
|
|
318
340
|
def column_names
|
|
@@ -337,34 +359,29 @@ module ActiveRecord
|
|
|
337
359
|
vector = args.count.zero? ? name : [[name] + args]
|
|
338
360
|
@backing_record.get_server_method(vector, true)
|
|
339
361
|
end
|
|
362
|
+
define_method("_hyperstack_internal_setter_#{name}") do |val|
|
|
363
|
+
backing_record.set_attr_value(name, val)
|
|
364
|
+
end
|
|
340
365
|
end
|
|
341
366
|
|
|
342
|
-
#
|
|
343
|
-
#
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
# define_method(name) { @backing_record.get_attr_value(name, nil) } unless method_defined?(name)
|
|
348
|
-
# define_method("#{name}!") { @backing_record.get_attr_value(name, true) } unless method_defined?("#{name}!")
|
|
349
|
-
# define_method("#{name}=") { |val| @backing_record.set_attr_value(name, val) } unless method_defined?("#{name}=")
|
|
350
|
-
# define_method("#{name}_changed?") { @backing_record.changed?(name) } unless method_defined?("#{name}_changed?")
|
|
351
|
-
# define_method("#{name}?") { @backing_record.get_attr_value(name, nil).present? } unless method_defined?("#{name}?")
|
|
352
|
-
# end
|
|
353
|
-
# self.inheritance_column = nil if inheritance_column && !columns_hash.key?(inheritance_column)
|
|
354
|
-
# end
|
|
355
|
-
|
|
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.
|
|
356
372
|
|
|
357
373
|
def define_attribute_methods
|
|
358
374
|
columns_hash.each do |name, column_hash|
|
|
359
|
-
next if name ==
|
|
375
|
+
next if name == :id
|
|
360
376
|
# only add serialized key if its serialized. This just makes testing a bit
|
|
361
377
|
# easier by keeping the columns_hash the same if there are no seralized strings
|
|
362
378
|
# see rspec ./spec/batch1/column_types/column_type_spec.rb:100
|
|
363
379
|
column_hash[:serialized?] = true if ReactiveRecord::Base.serialized?[self][name]
|
|
364
|
-
|
|
380
|
+
|
|
365
381
|
define_method(name) { @backing_record.get_attr_value(name, nil) } unless method_defined?(name)
|
|
366
382
|
define_method("#{name}!") { @backing_record.get_attr_value(name, true) } unless method_defined?("#{name}!")
|
|
367
|
-
define_method("#{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}=")
|
|
368
385
|
define_method("#{name}_changed?") { @backing_record.changed?(name) } unless method_defined?("#{name}_changed?")
|
|
369
386
|
define_method("#{name}?") { @backing_record.get_attr_value(name, nil).present? } unless method_defined?("#{name}?")
|
|
370
387
|
end
|
|
@@ -397,18 +414,23 @@ module ActiveRecord
|
|
|
397
414
|
associations = reflect_on_all_associations
|
|
398
415
|
|
|
399
416
|
already_processed_keys = Set.new
|
|
400
|
-
old_param = param.dup
|
|
401
417
|
|
|
402
418
|
param = param.collect do |key, value|
|
|
403
419
|
next if already_processed_keys.include? key
|
|
404
420
|
|
|
405
421
|
model_name = model_id = nil
|
|
406
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
|
+
|
|
407
429
|
assoc = associations.detect do |poly_assoc|
|
|
408
430
|
if key == poly_assoc.polymorphic_type_attribute
|
|
409
431
|
model_name = value
|
|
410
432
|
already_processed_keys << poly_assoc.association_foreign_key
|
|
411
|
-
elsif key == poly_assoc.association_foreign_key
|
|
433
|
+
elsif key == poly_assoc.association_foreign_key && (poly_assoc.polymorphic_type_attribute || poly_assoc.macro == :belongs_to)
|
|
412
434
|
model_id = value
|
|
413
435
|
already_processed_keys << poly_assoc.polymorphic_type_attribute
|
|
414
436
|
end
|
|
@@ -440,7 +462,7 @@ module ActiveRecord
|
|
|
440
462
|
[assoc.attribute, { id: [value]}]
|
|
441
463
|
end
|
|
442
464
|
else
|
|
443
|
-
[key, [value]]
|
|
465
|
+
[*key, [value]]
|
|
444
466
|
end
|
|
445
467
|
end.compact
|
|
446
468
|
ReactiveRecord::Base.load_data do
|
|
@@ -1,7 +1,34 @@
|
|
|
1
1
|
module ActiveRecord
|
|
2
2
|
module InstanceMethods
|
|
3
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
|
+
|
|
4
30
|
def method_missing(missing, *args, &block)
|
|
31
|
+
missing ||= `Opal.__name_of_super`
|
|
5
32
|
column = self.class.columns_hash.detect { |name, *| missing =~ /^#{name}/ }
|
|
6
33
|
if column
|
|
7
34
|
name = column[0]
|
|
@@ -17,6 +44,16 @@ module ActiveRecord
|
|
|
17
44
|
end
|
|
18
45
|
end
|
|
19
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
|
+
|
|
20
57
|
def inspect
|
|
21
58
|
"<#{model_name}:#{ReactiveRecord::Operations::Base::FORMAT % to_key} "\
|
|
22
59
|
"(#{ReactiveRecord::Operations::Base::FORMAT % object_id}) "\
|
|
@@ -55,7 +92,7 @@ module ActiveRecord
|
|
|
55
92
|
end
|
|
56
93
|
self.class.load_data do
|
|
57
94
|
h.each do |attribute, value|
|
|
58
|
-
next if attribute ==
|
|
95
|
+
next if attribute == :id
|
|
59
96
|
@ar_instance[attribute] = value
|
|
60
97
|
changed_attributes << attribute
|
|
61
98
|
end
|
|
@@ -89,8 +126,8 @@ module ActiveRecord
|
|
|
89
126
|
@backing_record.revert
|
|
90
127
|
end
|
|
91
128
|
|
|
92
|
-
def changed?
|
|
93
|
-
@backing_record.changed?
|
|
129
|
+
def changed?(attr = nil)
|
|
130
|
+
@backing_record.changed?(*attr)
|
|
94
131
|
end
|
|
95
132
|
|
|
96
133
|
def dup
|
|
@@ -125,6 +162,14 @@ module ActiveRecord
|
|
|
125
162
|
# end
|
|
126
163
|
end
|
|
127
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
|
+
|
|
128
173
|
def load(*attributes, &block)
|
|
129
174
|
first_time = true
|
|
130
175
|
ReactiveRecord.load do
|