hyper-model 1.0.alpha1.5 → 1.0.alpha1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|