hyper-mesh 1.0.0.lap27 → 1.0.0.lap28

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +6 -2
  4. data/Gemfile +0 -1
  5. data/Rakefile +2 -2
  6. data/hyper-mesh.gemspec +1 -1
  7. data/lib/active_record_base.rb +39 -27
  8. data/lib/hyper-mesh.rb +6 -1
  9. data/lib/hypermesh/version.rb +1 -1
  10. data/lib/object/tap.rb +7 -0
  11. data/lib/reactive_record/active_record/associations.rb +14 -3
  12. data/lib/reactive_record/active_record/base.rb +1 -2
  13. data/lib/reactive_record/active_record/class_methods.rb +120 -67
  14. data/lib/reactive_record/active_record/error.rb +17 -12
  15. data/lib/reactive_record/active_record/errors.rb +374 -0
  16. data/lib/reactive_record/active_record/instance_methods.rb +58 -67
  17. data/lib/reactive_record/active_record/reactive_record/backing_record_inspector.rb +1 -4
  18. data/lib/reactive_record/active_record/reactive_record/base.rb +129 -234
  19. data/lib/reactive_record/active_record/reactive_record/collection.rb +51 -18
  20. data/lib/reactive_record/active_record/reactive_record/column_types.rb +5 -3
  21. data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +6 -4
  22. data/lib/reactive_record/active_record/reactive_record/getters.rb +133 -0
  23. data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +99 -87
  24. data/lib/reactive_record/active_record/reactive_record/lookup_tables.rb +54 -0
  25. data/lib/reactive_record/active_record/reactive_record/operations.rb +2 -1
  26. data/lib/reactive_record/active_record/reactive_record/scoped_collection.rb +1 -1
  27. data/lib/reactive_record/active_record/reactive_record/setters.rb +194 -0
  28. data/lib/reactive_record/active_record/reactive_record/while_loading.rb +4 -5
  29. data/lib/reactive_record/active_record_error.rb +4 -0
  30. data/lib/reactive_record/broadcast.rb +55 -18
  31. data/lib/reactive_record/permissions.rb +5 -4
  32. data/lib/reactive_record/scope_description.rb +14 -6
  33. data/lib/reactive_record/server_data_cache.rb +119 -70
  34. metadata +16 -13
  35. data/lib/reactive_record/active_record/reactive_record/reactive_set_relationship_helpers.rb +0 -189
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae2e1bd29b4c0fd94efb2466949a271d478a5585d2e81045e88871c02e412256
4
- data.tar.gz: abf0a91cc51d3b62e3053392082b0df4a1f80113bb0cd3d8876aca6fbb994a54
3
+ metadata.gz: 496e78b04675fc8421cf1bf977361c6a6049769a8fd2d2dd9c0f0766735a41d5
4
+ data.tar.gz: 55513ce6b73c89665be0dddc74843cc59df11079233569ea404302eb10eddd1f
5
5
  SHA512:
6
- metadata.gz: 7867946eaf76d99ef08323ccbf6c78fe20c7cb440e4cbe43b379bbd34e5ea168808b3d525c8649ce04f20e5ea37f196b6b1a1b0f7a0bca849abbbc14373c97f5
7
- data.tar.gz: 820061867257b00bb28cedfc11212e3f5d0a28439a1080c0aca2651977673ea13eb9a6d997fca5a7b4dd333ffa1f88ceca07daa4923f7ed682c2b2a6ccf42156
6
+ metadata.gz: a0a0152a43aaeb0e3ecadc152db2e71a3a0fe24e4775ead3f95276c5d4d8351b53d8ef2e766309bdb36b574273b3ae0bb845b2d2d38ba2363dcda2a59892ace3
7
+ data.tar.gz: 3316b9c3a125034a8bbed27a5263412f863b160dd7246eec08bddba0f081623fb11df34c3e51b52f2fce8faae522335171c988905e5fc54635210b7846cb7cd1
data/.gitignore CHANGED
@@ -17,6 +17,7 @@ spec/test_app/Gemfile.lock
17
17
  /Gemfile.lock
18
18
  /examples/action-cable/rails_cache_dir/
19
19
  rails_cache_dir/
20
+ react_prerendering_src.js
20
21
 
21
22
  .bundle/
22
23
  log/*.log
@@ -1,11 +1,15 @@
1
+
1
2
  Metrics/LineLength:
2
3
  Max: 100
3
4
 
4
5
  Style/MutableConstant:
5
6
  Enabled: false
6
7
 
7
- Lint/LiteralInCondition:
8
- Enabled: false
8
+ # Lint/LiteralInCondition:
9
+ # Enabled: false
9
10
 
10
11
  Style/CommandLiteral:
11
12
  EnforcedStyle: mixed
13
+
14
+ AllCops:
15
+ TargetRubyVersion: 2.4.1
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source 'https://rubygems.org'
2
- gem 'hyper-operation', git: 'https://github.com/ruby-hyperloop/hyper-operation.git', branch: 'edge'
3
2
  gem "opal-jquery", git: "https://github.com/opal/opal-jquery.git", branch: "master"
4
3
  gemspec
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require "rspec/core/rake_task"
4
4
 
5
5
 
6
6
  task :spec do
7
- (1..6).each { |batch| Rake::Task["spec:batch#{batch}"].invoke }
7
+ (1..7).each { |batch| Rake::Task["spec:batch#{batch}"].invoke rescue nil }
8
8
  end
9
9
 
10
10
  namespace :spec do
@@ -12,7 +12,7 @@ namespace :spec do
12
12
  sh %{bundle update}
13
13
  sh %{cd spec/test_app; bundle update; bundle exec rails db:setup} # may need ;bundle exec rails db:setup as well
14
14
  end
15
- (1..6).each do |batch|
15
+ (1..7).each do |batch|
16
16
  RSpec::Core::RakeTask.new(:"batch#{batch}") do |t|
17
17
  t.pattern = "spec/batch#{batch}/**/*_spec.rb"
18
18
  end
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  # }
22
22
 
23
23
  spec.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(examples|gemfiles|pkg|reactive_record_test_app|spec)/}) }
24
- spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
24
+ # spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
25
25
  spec.test_files = `git ls-files -- {spec}/*`.split("\n")
26
26
  spec.require_paths = ['lib']
27
27
 
@@ -41,7 +41,7 @@ module ActiveRecord
41
41
  attr_accessor :acting_user
42
42
  def __secure_collection_check(acting_user)
43
43
  return self if __synchromesh_permission_granted
44
- return self if __secure_remote_access_to_unscoped(acting_user).__synchromesh_permission_granted
44
+ return self if __secure_remote_access_to_unscoped(self, acting_user).__synchromesh_permission_granted
45
45
  denied!
46
46
  end
47
47
  end
@@ -62,11 +62,11 @@ module ActiveRecord
62
62
  # Here we set up the base `all` and `unscoped` methods. See below for more on how
63
63
  # access protection works on relationships.
64
64
 
65
- def __secure_remote_access_to_all(_acting_user)
65
+ def __secure_remote_access_to_all(_self, _acting_user)
66
66
  all
67
67
  end
68
68
 
69
- def __secure_remote_access_to_unscoped(_acting_user, *args)
69
+ def __secure_remote_access_to_unscoped(_self, _acting_user, *args)
70
70
  unscoped(*args)
71
71
  end
72
72
 
@@ -77,8 +77,8 @@ module ActiveRecord
77
77
  # For finder_method we have to preapply `all` so that we always have a relationship
78
78
 
79
79
  def finder_method(name, &block)
80
- singleton_class.send(:define_method, :"__secure_remote_access_to__#{name}") do |acting_user, *args|
81
- this = respond_to?(:acting_user) ? self : all
80
+ singleton_class.send(:define_method, :"__secure_remote_access_to__#{name}") do |this, acting_user, *args|
81
+ this = respond_to?(:acting_user) ? this : all
82
82
  begin
83
83
  old = this.acting_user
84
84
  this.acting_user = acting_user
@@ -98,7 +98,7 @@ module ActiveRecord
98
98
  # callable from the server internally
99
99
  define_method(name, &block)
100
100
  # callable remotely from the client
101
- define_method("__secure_remote_access_to_#{name}") do |acting_user, *args|
101
+ define_method("__secure_remote_access_to_#{name}") do |_self, acting_user, *args|
102
102
  begin
103
103
  old = self.acting_user
104
104
  self.acting_user = acting_user
@@ -166,17 +166,17 @@ module ActiveRecord
166
166
  end
167
167
 
168
168
  # helper method to set the value of __synchromesh_permission_granted on the relationship
169
- # Get the current value of __synchromesh_permission_granted, set acting_user on the
170
- # object, and or in the result of running the block in context of the obj
169
+ # Set acting_user on the object, then or in the result of running the block in context
170
+ # of the obj with the current value of __synchromesh_permission_granted
171
171
 
172
- def __set_synchromesh_permission_granted(r, obj, acting_user, args = [], &block)
173
- r.__synchromesh_permission_granted = try(:__synchromesh_permission_granted)
174
- old = acting_user
172
+ def __set_synchromesh_permission_granted(old_rel, new_rel, obj, acting_user, args = [], &block)
173
+ saved_acting_user = obj.acting_user
175
174
  obj.acting_user = acting_user
176
- r.__synchromesh_permission_granted ||= obj.instance_exec(*args, &block)
177
- r
175
+ new_rel.__synchromesh_permission_granted =
176
+ obj.instance_exec(*args, &block) || (old_rel && old_rel.try(:__synchromesh_permission_granted))
177
+ new_rel
178
178
  ensure
179
- obj.acting_user = old
179
+ obj.acting_user = saved_acting_user
180
180
  end
181
181
 
182
182
  # regulate scope has to deal with the special case that the scope returns an
@@ -184,16 +184,17 @@ module ActiveRecord
184
184
 
185
185
  def regulate_scope(name, &block)
186
186
  name, block = __synchromesh_parse_regulator_params(name, block)
187
- singleton_class.send(:define_method, :"__secure_remote_access_to_#{name}") do |acting_user, *args|
188
- r = send(name, *args)
187
+ singleton_class.send(:define_method, :"__secure_remote_access_to_#{name}") do |this, acting_user, *args|
188
+ r = this.send(name, *args)
189
189
  r = ReactiveRecordPsuedoRelationArray.new(r) if r.is_a? Array
190
- __set_synchromesh_permission_granted(r, r, acting_user, args, &block)
190
+ __set_synchromesh_permission_granted(this, r, r, acting_user, args, &block)
191
191
  end
192
192
  end
193
193
 
194
194
  # regulate_default_scope
195
195
 
196
- def regulate_default_scope(&block)
196
+ def regulate_default_scope(*args, &block)
197
+ block = __synchromesh_parse_regulator_params({ all: args[0] }, block).last unless args.empty?
197
198
  regulate_scope(:all, &block)
198
199
  end
199
200
 
@@ -229,9 +230,9 @@ module ActiveRecord
229
230
 
230
231
  def regulate_relationship(name, &block)
231
232
  name, block = __synchromesh_parse_regulator_params(name, block)
232
- define_method(:"__secure_remote_access_to_#{name}") do |acting_user, *args|
233
- self.class.__set_synchromesh_permission_granted(
234
- send(name, *args), self, acting_user, &block
233
+ define_method(:"__secure_remote_access_to_#{name}") do |this, acting_user, *args|
234
+ this.class.__set_synchromesh_permission_granted(
235
+ nil, this.send(name, *args), this, acting_user, &block
235
236
  )
236
237
  end
237
238
  end
@@ -254,21 +255,21 @@ module ActiveRecord
254
255
  # simply return `find(1)` but if you try returning `find(1).name` the permission system
255
256
  # will check to see if the name attribute can be legally sent to the current acting user.
256
257
 
257
- def __secure_remote_access_to_find(_acting_user, *args)
258
+ def __secure_remote_access_to_find(_self, _acting_user, *args)
258
259
  find(*args)
259
260
  end
260
261
 
261
- def __secure_remote_access_to_find_by(_acting_user, *args)
262
+ def __secure_remote_access_to_find_by(_self, _acting_user, *args)
262
263
  find_by(*args)
263
264
  end
264
265
 
265
266
  %i[belongs_to has_one].each do |macro|
266
267
  alias_method :"pre_syncromesh_#{macro}", macro
267
- define_method(macro) do |name, scope = nil, opts = {}, &block|
268
- define_method(:"__secure_remote_access_to_#{name}") do |_acting_user, *args|
269
- send(name, *args)
268
+ define_method(macro) do |name, *aargs, &block|
269
+ define_method(:"__secure_remote_access_to_#{name}") do |this, _acting_user, *args|
270
+ this.send(name, *args)
270
271
  end
271
- send(:"pre_syncromesh_#{macro}", name, scope, opts, &block)
272
+ send(:"pre_syncromesh_#{macro}", name, *aargs, &block)
272
273
  end
273
274
  end
274
275
  end
@@ -311,6 +312,17 @@ module ActiveRecord
311
312
  return if do_not_synchronize?
312
313
  ReactiveRecord::Broadcast.after_commit :destroy, self
313
314
  end
315
+
316
+ def __hyperloop_secure_attributes(acting_user)
317
+ accessible_attributes =
318
+ Hyperloop::InternalPolicy.accessible_attributes_for(self, acting_user)
319
+ attributes.select { |attr| accessible_attributes.include? attr.to_sym }
320
+ end
321
+
322
+ # regulate built in scopes so they are accesible from the client
323
+ %i[limit offset].each do |scope|
324
+ regulate_scope(scope) {}
325
+ end
314
326
  end
315
327
  end
316
328
 
@@ -7,6 +7,9 @@ if RUBY_ENGINE == 'opal'
7
7
  require 'time'
8
8
  require 'date'
9
9
  require 'kernel/itself' unless Object.instance_methods.include?(:itself)
10
+ require 'object/tap'
11
+ require "reactive_record/active_record_error"
12
+ require "reactive_record/active_record/errors"
10
13
  require "reactive_record/active_record/error"
11
14
  require "reactive_record/server_data_cache"
12
15
  require "reactive_record/active_record/reactive_record/while_loading"
@@ -18,8 +21,10 @@ if RUBY_ENGINE == 'opal'
18
21
  require "reactive_record/active_record/aggregations"
19
22
  require "reactive_record/active_record/associations"
20
23
  require "reactive_record/active_record/reactive_record/backing_record_inspector"
24
+ require "reactive_record/active_record/reactive_record/getters"
25
+ require "reactive_record/active_record/reactive_record/setters"
26
+ require "reactive_record/active_record/reactive_record/lookup_tables"
21
27
  require "reactive_record/active_record/reactive_record/base"
22
- require "reactive_record/active_record/reactive_record/reactive_set_relationship_helpers"
23
28
  require "reactive_record/active_record/reactive_record/collection"
24
29
  require "reactive_record/active_record/reactive_record/scoped_collection"
25
30
  require "reactive_record/active_record/reactive_record/unscoped_collection"
@@ -1,3 +1,3 @@
1
1
  module Hypermesh
2
- VERSION = '1.0.0.lap27'
2
+ VERSION = '1.0.0.lap28'
3
3
  end
@@ -0,0 +1,7 @@
1
+ class Object
2
+ def tap
3
+ val = `self.$$is_boolean` ? self==true : self
4
+ yield val
5
+ val
6
+ end
7
+ end
@@ -6,13 +6,24 @@ module ActiveRecord
6
6
  base_class.instance_eval { @associations ||= superclass.instance_eval { (@associations && @associations.dup) || [] } }
7
7
  end
8
8
 
9
- def self.reflect_on_association(attribute)
10
- if found = reflect_on_all_associations.detect { |association| association.attribute == attribute and association.owner_class == self }
9
+ def self.reflect_on_association(attr)
10
+ reflection_finder { |assoc| assoc.attribute == attr }
11
+ end
12
+
13
+ def self.reflect_on_association_by_foreign_key(key)
14
+ reflection_finder { |assoc| assoc.association_foreign_key == key }
15
+ end
16
+
17
+ def self.reflection_finder(&block)
18
+ found = reflect_on_all_associations.detect do |assoc|
19
+ assoc.owner_class == self && yield(assoc)
20
+ end
21
+ if found
11
22
  found
12
23
  elsif superclass == Base
13
24
  nil
14
25
  else
15
- superclass.reflect_on_association(attribute)
26
+ superclass.reflection_finder(&block)
16
27
  end
17
28
  end
18
29
 
@@ -1,9 +1,8 @@
1
1
  module ActiveRecord
2
2
  # client side ActiveRecord::Base proxy
3
3
  class Base
4
- extend ClassMethods
5
-
6
4
  include InstanceMethods
5
+ extend ClassMethods
7
6
 
8
7
  scope :limit, ->() {}
9
8
  scope :offset, ->() {}
@@ -2,10 +2,15 @@ module ActiveRecord
2
2
 
3
3
  module ClassMethods
4
4
 
5
- def base_class
5
+ alias _new_without_sti_type_cast new
6
+
7
+ def new(*args, &block)
8
+ _new_without_sti_type_cast(*args, &block).cast_to_current_sti_type
9
+ end
6
10
 
11
+ def base_class
7
12
  unless self < Base
8
- raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
13
+ raise ActiveRecordError, "#{name} doesn't descend from ActiveRecord"
9
14
  end
10
15
 
11
16
  if superclass == Base || superclass.abstract_class?
@@ -13,7 +18,6 @@ module ActiveRecord
13
18
  else
14
19
  superclass.base_class
15
20
  end
16
-
17
21
  end
18
22
 
19
23
  def abstract_class?
@@ -21,19 +25,26 @@ module ActiveRecord
21
25
  end
22
26
 
23
27
  def primary_key
24
- base_class.instance_eval { @primary_key_value || :id }
28
+ @primary_key_value ||= (self == base_class) ? :id : base_class.primary_key
25
29
  end
26
30
 
27
31
  def primary_key=(val)
28
- base_class.instance_eval { @primary_key_value = val }
32
+ @primary_key_value = val.to_s
29
33
  end
30
34
 
31
35
  def inheritance_column
32
- base_class.instance_eval {@inheritance_column_value || "type"}
36
+ return nil if @no_inheritance_column
37
+ @inheritance_column_value ||=
38
+ if self == base_class
39
+ @inheritance_column_value || 'type'
40
+ else
41
+ superclass.inheritance_column.tap { |v| @no_inheritance_column = !v }
42
+ end
33
43
  end
34
44
 
35
45
  def inheritance_column=(name)
36
- base_class.instance_eval {@inheritance_column_value = name}
46
+ @no_inheritance_column = !name
47
+ @inheritance_column_value = name
37
48
  end
38
49
 
39
50
  def model_name
@@ -42,11 +53,13 @@ module ActiveRecord
42
53
  end
43
54
 
44
55
  def find(id)
45
- base_class.instance_eval {ReactiveRecord::Base.find(self, primary_key, id)}
56
+ ReactiveRecord::Base.find(self, primary_key => id)
46
57
  end
47
58
 
48
59
  def find_by(opts = {})
49
- base_class.instance_eval {ReactiveRecord::Base.find(self, opts.first.first, opts.first.last)}
60
+ dealiased_opts = {}
61
+ opts.each { |attr, value| dealiased_opts[_dealias_attribute(attr)] = value }
62
+ ReactiveRecord::Base.find(self, dealiased_opts)
50
63
  end
51
64
 
52
65
  def enum(*args)
@@ -57,6 +70,25 @@ module ActiveRecord
57
70
  ReactiveRecord::Base.serialized?[self][attr] = true
58
71
  end
59
72
 
73
+ def _dealias_attribute(new)
74
+ if self == base_class
75
+ _attribute_aliases[new] || new
76
+ else
77
+ _attribute_aliases[new] ||= superclass._dealias_attribute(new)
78
+ end
79
+ end
80
+
81
+ def _attribute_aliases
82
+ @_attribute_aliases ||= {}
83
+ end
84
+
85
+ def alias_attribute(new_name, old_name)
86
+ ['', '=', '_changed?'].each do |variant|
87
+ define_method("#{new_name}#{variant}") { |*args, &block| send("#{old_name}#{variant}", *args, &block) }
88
+ end
89
+ _attribute_aliases[new_name] = old_name
90
+ end
91
+
60
92
  # ignore any of these methods if they get called on the client. This list should be trimmed down to include only
61
93
  # methods to be called as "macros" such as :after_create, etc...
62
94
  SERVER_METHODS = [
@@ -145,7 +177,7 @@ module ActiveRecord
145
177
 
146
178
  def method_missing(name, *args, &block)
147
179
  if args.count == 1 && name.start_with?("find_by_") && !block
148
- find_by(name.sub(/^find_by_/, "") => args[0])
180
+ find_by(_dealias_attribute(name.sub(/^find_by_/, "")) => args[0])
149
181
  elsif [].respond_to?(name)
150
182
  all.send(name, *args, &block)
151
183
  elsif name.end_with?('!')
@@ -199,12 +231,25 @@ module ActiveRecord
199
231
  root = ReactiveRecord::Collection
200
232
  .new(self, nil, nil, self, 'all')
201
233
  .extend(ReactiveRecord::UnscopedCollection)
202
- (@_default_scopes || [{ client: -> () { true } }]).inject(root) do |scope, opts|
234
+ (@_default_scopes || [{ client: _all_filter }]).inject(root) do |scope, opts|
203
235
  scope.build_child_scope(ReactiveRecord::ScopeDescription.new(self, :all, opts))
204
236
  end
205
237
  end
206
238
  end
207
239
 
240
+ def _all_filter
241
+ # provides a filter for the all scopes taking into account STI subclasses
242
+ # note: within the lambda `self` will be the model instance
243
+ defining_class_is_base_class = base_class == self
244
+ defining_model_name = model_name
245
+ lambda do
246
+ # have to delay computation of inheritance column since it might
247
+ # not be defined when class is first defined
248
+ ic = self.class.inheritance_column
249
+ defining_class_is_base_class || !ic || self[ic] == defining_model_name
250
+ end
251
+ end
252
+
208
253
  # def all=(_collection)
209
254
  # raise "NO LONGER IMPLEMENTED DOESNT PLAY WELL WITH SYNCHROMESH"
210
255
  # end
@@ -250,20 +295,27 @@ module ActiveRecord
250
295
  [:belongs_to, :has_many, :has_one].each do |macro|
251
296
  define_method(macro) do |*args| # is this a bug in opal? saying name, scope=nil, opts={} does not work!
252
297
  name = args.first
253
- define_method(name) { @backing_record.reactive_get!(name, nil) }
254
- define_method("#{name}=") do |val|
255
- @backing_record.reactive_set!(name, backing_record.convert(name, val).itself)
256
- end
257
298
  opts = (args.count > 1 and args.last.is_a? Hash) ? args.last : {}
258
- Associations::AssociationReflection.new(self, macro, name, opts)
299
+ assoc = Associations::AssociationReflection.new(self, macro, name, opts)
300
+ if macro == :has_many
301
+ define_method(name) { @backing_record.get_has_many(assoc, nil) }
302
+ define_method("#{name}=") { |val| @backing_record.set_has_many(assoc, val) }
303
+ else
304
+ define_method(name) { @backing_record.get_belongs_to(assoc, nil) }
305
+ define_method("#{name}=") { |val| @backing_record.set_belongs_to(assoc, val) }
306
+ end
307
+ assoc
259
308
  end
260
309
  end
261
310
 
262
311
  def composed_of(name, opts = {})
263
- Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
264
- define_method(name) { @backing_record.reactive_get!(name, nil) }
265
- define_method("#{name}=") do |val|
266
- @backing_record.reactive_set!(name, backing_record.convert(name, val))
312
+ reflection = Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
313
+ if reflection.klass < ActiveRecord::Base
314
+ define_method(name) { @backing_record.get_ar_aggregate(reflection, nil) }
315
+ define_method("#{name}=") { |val| @backing_record.set_ar_aggregate(reflection, val) }
316
+ else
317
+ define_method(name) { @backing_record.get_non_ar_aggregate(name, nil) }
318
+ define_method("#{name}=") { |val| @backing_record.set_non_ar_aggregate(reflection, val) }
267
319
  end
268
320
  end
269
321
 
@@ -282,73 +334,74 @@ module ActiveRecord
282
334
  def server_method(name, default: nil)
283
335
  server_methods[name] = { default: default }
284
336
  define_method(name) do |*args|
285
- vector = args.count.zero? ? name : [[name]+args]
286
- @backing_record.reactive_get!(vector, nil)
337
+ vector = args.count.zero? ? name : [[name] + args]
338
+ @backing_record.get_server_method(vector, nil)
287
339
  end
288
340
  define_method("#{name}!") do |*args|
289
- vector = args.count.zero? ? name : [[name]+args]
290
- @backing_record.reactive_get!(vector, true)
341
+ vector = args.count.zero? ? name : [[name] + args]
342
+ @backing_record.get_server_method(vector, true)
291
343
  end
292
344
  end
293
345
 
294
346
  def define_attribute_methods
295
- columns_hash.keys.each do |name|
296
- next if name == :id
297
- define_method(name) { @backing_record.reactive_get!(name, nil) }
298
- define_method("#{name}!") { @backing_record.reactive_get!(name, true) }
299
- define_method("#{name}=") do |val|
300
- @backing_record.reactive_set!(name, backing_record.convert(name, val))
301
- end
347
+ columns_hash.each do |name, column_hash|
348
+ next if name == primary_key
349
+ define_method(name) { @backing_record.get_attr_value(name, nil) }
350
+ define_method("#{name}!") { @backing_record.get_attr_value(name, true) }
351
+ define_method("#{name}=") { |val| @backing_record.set_attr_value(name, val) }
302
352
  define_method("#{name}_changed?") { @backing_record.changed?(name) }
353
+ define_method("#{name}?") { @backing_record.get_attr_value(name, nil).present? }
303
354
  end
355
+ self.inheritance_column = nil if inheritance_column && !columns_hash.key?(inheritance_column)
304
356
  end
305
357
 
306
358
  def _react_param_conversion(param, opt = nil)
307
359
  param = Native(param)
308
360
  param = JSON.from_object(param.to_n) if param.is_a? Native::Object
309
- result = if param.is_a? self
310
- param
311
- elsif param.is_a? Hash
312
- if opt == :validate_only
313
- klass = ReactiveRecord::Base.infer_type_from_hash(self, param)
314
- klass == self or klass < self
315
- else
316
- if param[primary_key]
317
- target = find(param[primary_key])
361
+ result =
362
+ if param.is_a? self
363
+ param
364
+ elsif param.is_a? Hash
365
+ if opt == :validate_only
366
+ klass = ReactiveRecord::Base.infer_type_from_hash(self, param)
367
+ klass == self || klass < self
318
368
  else
319
- target = new
320
- end
321
- associations = reflect_on_all_associations
322
- param = param.collect do |key, value|
323
- assoc = reflect_on_all_associations.detect do |assoc|
324
- assoc.association_foreign_key == key
325
- end
326
- if assoc
327
- if value
328
- [assoc.attribute, {id: [value], type: [nil]}]
369
+ # TODO: investigate saving .changes here and then replacing the
370
+ # TODO: changes after the load is complete. In other words preserve the
371
+ # TODO: changed values as changes while just updating the synced values.
372
+ target =
373
+ if param[primary_key]
374
+ find(param[primary_key])
329
375
  else
330
- [assoc.attribute, [nil]]
376
+ new
331
377
  end
332
- else
333
- [key, [value]]
334
- end
335
- end
336
378
 
337
- # We do want to be doing something like this, but this breaks other stuff...
338
- #
339
- # ReactiveRecord::Base.load_data do
340
- # ReactiveRecord::ServerDataCache.load_from_json(Hash[param], target)
341
- # end
379
+ associations = reflect_on_all_associations
380
+
381
+ param = param.collect do |key, value|
382
+ assoc = associations.detect do |association|
383
+ association.association_foreign_key == key
384
+ end
342
385
 
343
- ReactiveRecord::ServerDataCache.load_from_json(Hash[param], target)
344
- target
386
+ if assoc
387
+ if value
388
+ [assoc.attribute, { id: [value] }]
389
+ else
390
+ [assoc.attribute, [nil]]
391
+ end
392
+ else
393
+ [key, [value]]
394
+ end
395
+ end
396
+ # TODO: verify wrapping with load_data was added so broadcasting works in 1.0.0.lap28
397
+ ReactiveRecord::Base.load_data do
398
+ ReactiveRecord::ServerDataCache.load_from_json(Hash[param], target)
399
+ end
400
+ target.cast_to_current_sti_type
401
+ end
345
402
  end
346
- else
347
- nil
348
- end
403
+
349
404
  result
350
405
  end
351
-
352
406
  end
353
-
354
407
  end