hyper-mesh 1.0.0.lap27 → 1.0.0.lap28

Sign up to get free protection for your applications and to get access to all the features.
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