reactive-record 0.7.20 → 0.7.22

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6c2c4283d8c482a6dc3b9ca9f0c9980ce4a9bad8
4
- data.tar.gz: 55dbf1be5bc98e3bfa115f4e13e10591e3febf78
3
+ metadata.gz: 8ac17cb9431cfb70da2b36ad364d6f6daddabfad
4
+ data.tar.gz: 1ce72b88c991bcd5bd7b2b643a64c10b0da1173b
5
5
  SHA512:
6
- metadata.gz: 9d827bab1ca8da5f8321808357a97e32b33151de2a04e2c7e89826b84b8e54ebd6b543edcbc76675b5ed3e501a447082a59a6a3e336b4e9bee98c7eb0f043de3
7
- data.tar.gz: 2f8e98cabf83f5bdf67c4e27e51aa0ead8917de7e25b0bc53d91a5f22bd473c8a600cb018c767d50f5d517cc54f287d8eb6d4c3e398fc24c374211683e826716
6
+ metadata.gz: 4f030a78f2bfb6be443e26f00a3782f33730abbfea6fcdf9897fde842436e14f113cd7c2d152ed2280536ef245e67ec91629c97080f1fbb4e6a882b8a00baabc
7
+ data.tar.gz: 8ced444a4e20aeabba7536f3acddfee6aad92c195f9ffbee484955e53ba0714b08b8f6b53c35d71f28694cc32a65d49d6076581b283fc9fd2fcd68f385d754f6
@@ -1,5 +1,5 @@
1
1
  if RUBY_ENGINE == 'opal'
2
-
2
+
3
3
  require "reactive-ruby"
4
4
  require "reactive_record/active_record/error"
5
5
  require "reactive_record/server_data_cache"
@@ -13,30 +13,30 @@ if RUBY_ENGINE == 'opal'
13
13
  require "reactive_record/active_record/instance_methods"
14
14
  require "reactive_record/active_record/base"
15
15
  require "reactive_record/interval"
16
-
16
+
17
17
  else
18
-
18
+
19
19
  module ::ActiveRecord
20
20
  module Core
21
21
  module ClassMethods
22
- def inherited(child_class)
22
+ def inherited(child_class)
23
23
  begin
24
24
  file = Rails.root.join('app','models',"#{child_class.name.underscore}.rb").to_s rescue nil
25
- begin
26
- require file
25
+ begin
26
+ require file
27
27
  rescue LoadError
28
28
  end
29
29
  # from active record:
30
30
  child_class.initialize_find_by_cache
31
- rescue
31
+ rescue
32
32
  end
33
33
  super
34
34
  end
35
35
  end
36
36
  end
37
37
  end
38
-
39
-
38
+
39
+
40
40
  require "opal"
41
41
  require "reactive_record/version"
42
42
  require "reactive_record/permissions"
@@ -47,5 +47,5 @@ else
47
47
 
48
48
  Opal.append_path File.expand_path('../', __FILE__).untaint
49
49
  Opal.append_path File.expand_path('../../vendor', __FILE__).untaint
50
-
50
+
51
51
  end
@@ -63,7 +63,7 @@ module ActiveRecord
63
63
 
64
64
  def scope(name, body)
65
65
  singleton_class.send(:define_method, name) do | *args |
66
- args = args.count == 0 ? name : [name, *args]
66
+ args = (args.count == 0) ? name : [name, *args]
67
67
  ReactiveRecord::Base.class_scopes(self)[name] ||= ReactiveRecord::Collection.new(self, nil, nil, self, args)
68
68
  end
69
69
  singleton_class.send(:define_method, "#{name}=") do |collection|
@@ -89,6 +89,10 @@ module ActiveRecord
89
89
  @backing_record.destroy &block
90
90
  end
91
91
 
92
+ def destroyed?
93
+ @backing_record.destroyed
94
+ end
95
+
92
96
  def new?
93
97
  @backing_record.new?
94
98
  end
@@ -32,6 +32,7 @@ module ReactiveRecord
32
32
  attr_accessor :changed_attributes
33
33
  attr_accessor :aggregate_owner
34
34
  attr_accessor :aggregate_attribute
35
+ attr_accessor :destroyed
35
36
 
36
37
  # While data is being loaded from the server certain internal behaviors need to change
37
38
  # for example records all record changes are synced as they happen.
@@ -156,7 +157,11 @@ module ReactiveRecord
156
157
 
157
158
  def reactive_get!(attribute)
158
159
  unless @destroyed
159
- apply_method(attribute) unless @attributes.has_key? attribute
160
+ if @attributes.has_key? attribute
161
+ attributes[attribute].notify if @attributes[attribute].is_a? DummyValue
162
+ else
163
+ apply_method(attribute)
164
+ end
160
165
  React::State.get_state(self, attribute) unless data_loading?
161
166
  attributes[attribute]
162
167
  end
@@ -261,7 +266,7 @@ module ReactiveRecord
261
266
  @synced_attributes[key] = value.dup_for_sync
262
267
  elsif aggregation = model.reflect_on_aggregation(key)
263
268
  value.backing_record.sync!
264
- else
269
+ elsif !model.reflect_on_association(key)
265
270
  @synced_attributes[key] = JSON.parse(value.to_json)
266
271
  end
267
272
  end
@@ -36,14 +36,24 @@ module ReactiveRecord
36
36
  end
37
37
  else
38
38
  @dummy_collection = ReactiveRecord::Base.load_from_db(*@vector, "*all")
39
- @dummy_record = ReactiveRecord::Base.new_from_vector(@target_klass, nil, *@vector, "*")
40
- @dummy_record.backing_record.attributes[@association.inverse_of] = @owner if @association and @association.inverse_of
41
- @collection << @dummy_record
39
+ @dummy_record = self[0]
42
40
  end
43
41
  end
44
42
  @collection
45
43
  end
46
44
 
45
+ def [](index)
46
+
47
+ if (@collection || all).length <= index and @dummy_collection
48
+ (@collection.length..index).each do |i|
49
+ new_dummy_record = ReactiveRecord::Base.new_from_vector(@target_klass, nil, *@vector, "*#{i}")
50
+ new_dummy_record.backing_record.attributes[@association.inverse_of] = @owner if @association and @association.inverse_of
51
+ @collection << new_dummy_record
52
+ end
53
+ end
54
+ @collection[index]
55
+ end
56
+
47
57
  def ==(other_collection)
48
58
  my_collection = (@collection || []).select { |target| target != @dummy_record }
49
59
  other_collection = (other_collection ? (other_collection.collection || []) : []).select { |target| target != other_collection.dummy_record }
@@ -57,6 +67,19 @@ module ReactiveRecord
57
67
  @scopes[scope] ||= Collection.new(@target_klass, @owner, @association, *@vector, [scope])
58
68
  end
59
69
 
70
+ def count
71
+ if @collection
72
+ @collection.count
73
+ elsif @count ||= ReactiveRecord::Base.fetch_from_db([*@vector, "*count"])
74
+ @count
75
+ else
76
+ ReactiveRecord::Base.load_from_db(*@vector, "*count")
77
+ @count = 1
78
+ end
79
+ end
80
+
81
+ alias_method :length, :count
82
+
60
83
  def proxy_association
61
84
  @association || self # returning self allows this to work with things like Model.all
62
85
  end
@@ -65,24 +88,21 @@ module ReactiveRecord
65
88
  @target_klass
66
89
  end
67
90
 
68
-
69
91
  def <<(item)
70
92
  backing_record = item.backing_record
71
- # if backing_record and @owner and @association and inverse_of = @association.inverse_of
72
- # item.attributes[inverse_of].attributes[@association.attribute].delete(item) if item.attributes[inverse_of] and item.attributes[inverse_of].attributes[@association.attribute]
73
- # item.attributes[inverse_of] = @owner
74
- # React::State.set_state(backing_record, inverse_of, @owner) unless backing_record.data_loading?
75
- # end
76
- #all << item unless all.include? item
77
- all << item unless all.include? item
93
+ all << item unless all.include? item # does this use == if so we are okay...
78
94
  if backing_record and @owner and @association and inverse_of = @association.inverse_of and item.attributes[inverse_of] != @owner
79
95
  current_association = item.attributes[inverse_of]
80
96
  backing_record.update_attribute(inverse_of, @owner)
81
97
  current_association.attributes[@association.attribute].delete(item) if current_association and current_association.attributes[@association.attribute]
82
98
  @owner.backing_record.update_attribute(@association.attribute) # forces a check if association contents have changed from synced values
83
99
  end
84
- @collection.delete(@dummy_record)
85
- @dummy_record = @dummy_collection = nil
100
+ if item.id and @dummy_record
101
+ @dummy_record.id = item.id
102
+ @collection.delete(@dummy_record)
103
+ @dummy_record = @collection.detect { |r| r.backing_record.vector.last =~ /^\*[0-9]+$/ }
104
+ @dummy_collection = nil
105
+ end
86
106
  self
87
107
  end
88
108
 
@@ -97,9 +117,20 @@ module ReactiveRecord
97
117
  end
98
118
 
99
119
  def replace(new_array)
100
- #return new_array if @collection == new_array #not sure we need this anymore
101
- @dummy_collection.notify if @dummy_collection
102
- @collection.dup.each { |item| delete(item) } if @collection
120
+
121
+ # not tested if you do all[n] where n > 0... this will create additional dummy items, that this will not sync up.
122
+ # probably just moving things around so the @dummy_collection and @dummy_record are updated AFTER the new items are pushed
123
+ # should work.
124
+
125
+ if @dummy_collection
126
+ @dummy_collection.notify
127
+ array = new_array.is_a?(Collection) ? new_array.collection : new_array
128
+ @collection.each_with_index do |r, i|
129
+ r.id = new_array[i].id if array[i] and array[i].id and r.backing_record.vector.last =~ /^\*[0-9]+$/
130
+ end
131
+ end
132
+
133
+ @collection.dup.each { |item| delete(item) } if @collection # this line is a big nop I think
103
134
  @collection = []
104
135
  if new_array.is_a? Collection
105
136
  @dummy_collection = new_array.dummy_collection
@@ -124,6 +155,11 @@ module ReactiveRecord
124
155
  end
125
156
  end
126
157
 
158
+ def loading?
159
+ all # need to force initialization at this point
160
+ @dummy_collection.loading?
161
+ end
162
+
127
163
  def method_missing(method, *args, &block)
128
164
  if [].respond_to? method
129
165
  all.send(method, *args, &block)
@@ -86,70 +86,95 @@ module ReactiveRecord
86
86
  DummyValue.new
87
87
  end
88
88
 
89
- class DummyValue < NilClass
89
+ if RUBY_ENGINE == 'opal'
90
+ class ::Object
90
91
 
91
- def notify
92
- unless ReactiveRecord::Base.data_loading?
93
- ReactiveRecord.loads_pending! #loads
94
- ReactiveRecord::WhileLoading.loading! #loads
92
+ def loaded?
93
+ !loading?
94
+ end
95
+
96
+ def loading?
97
+ false
98
+ end
99
+
100
+ def present?
101
+ !!self
95
102
  end
96
- end
97
103
 
98
- def initialize()
99
- notify
100
104
  end
101
105
 
102
- def method_missing(method, *args, &block)
103
- if 0.respond_to? method
104
- notify
105
- 0.send(method, *args, &block)
106
- elsif "".respond_to? method
106
+ class DummyValue < NilClass
107
+
108
+ def notify
109
+ unless ReactiveRecord::Base.data_loading?
110
+ ReactiveRecord.loads_pending! #loads
111
+ ReactiveRecord::WhileLoading.loading! #loads
112
+ end
113
+ end
114
+
115
+ def initialize()
107
116
  notify
108
- "".send(method, *args, &block)
109
- else
110
- super
111
117
  end
112
- end
113
118
 
114
- def coerce(s)
115
- [self.send("to_#{s.class.name.downcase}"), s]
116
- end
119
+ def method_missing(method, *args, &block)
120
+ if 0.respond_to? method
121
+ notify
122
+ 0.send(method, *args, &block)
123
+ elsif "".respond_to? method
124
+ notify
125
+ "".send(method, *args, &block)
126
+ else
127
+ super
128
+ end
129
+ end
117
130
 
118
- def ==(other_value)
119
- other_value.is_a? DummyValue
120
- end
131
+ def loading?
132
+ true
133
+ end
121
134
 
122
- def to_s
123
- notify
124
- ""
125
- end
135
+ def present?
136
+ false
137
+ end
126
138
 
127
- def to_f
128
- notify
129
- 0.0
130
- end
139
+ def coerce(s)
140
+ [self.send("to_#{s.class.name.downcase}"), s]
141
+ end
131
142
 
132
- def to_i
133
- notify
134
- 0
135
- end
143
+ def ==(other_value)
144
+ other_value.object_id == self.object_id
145
+ end
136
146
 
137
- def to_numeric
138
- notify
139
- 0
140
- end
147
+ def to_s
148
+ notify
149
+ ""
150
+ end
141
151
 
142
- def to_date
143
- notify
144
- "2001-01-01T00:00:00.000-00:00".to_date
145
- end
152
+ def to_f
153
+ notify
154
+ 0.0
155
+ end
146
156
 
147
- def acts_as_string?
148
- true
149
- end
157
+ def to_i
158
+ notify
159
+ 0
160
+ end
150
161
 
151
- end
162
+ def to_numeric
163
+ notify
164
+ 0
165
+ end
152
166
 
167
+ def to_date
168
+ notify
169
+ "2001-01-01T00:00:00.000-00:00".to_date
170
+ end
171
+
172
+ def acts_as_string?
173
+ true
174
+ end
175
+
176
+ end
177
+ end
153
178
 
154
179
  def self.schedule_fetch
155
180
  #ReactiveRecord.loads_pending!
@@ -166,7 +191,7 @@ module ReactiveRecord
166
191
  begin
167
192
  ReactiveRecord::Base.load_from_json(response.json)
168
193
  rescue Exception => e
169
- log("Exception raised while loading json from server: #{e}", :error)
194
+ log("Unexpected exception raised while loading json from server: #{e}", :error)
170
195
  end
171
196
  log(" Processed in: #{(Time.now-fetch_time).to_i}s")
172
197
  log([" Returned: %o", response.json.to_n])
@@ -339,6 +364,8 @@ module ReactiveRecord
339
364
  puts "aggregate attributes after merge = #{aggregate.attributes}"
340
365
  parent.send("#{association[:attribute]}=", aggregate)
341
366
  puts "updated is frozen? #{aggregate.frozen?}, parent attributes = #{parent.send(association[:attribute]).attributes}"
367
+ elsif parent.class.reflect_on_association(association[:attribute].to_sym).nil?
368
+ raise "Missing association :#{association[:attribute]} for #{parent.class.name}. Was association defined on opal side only?"
342
369
  elsif parent.class.reflect_on_association(association[:attribute].to_sym).collection?
343
370
  puts ">>>>>>>>>> #{parent.class.name}.send('#{association[:attribute]}') << #{reactive_records[association[:child_id]]})"
344
371
  #parent.send("#{association[:attribute]}") << reactive_records[association[:child_id]]
@@ -417,8 +444,13 @@ module ReactiveRecord
417
444
  promise.resolve({success: true})
418
445
  end
419
446
 
420
- @attributes = {}
421
- sync!
447
+ # DO NOT CLEAR ATTRIBUTES. Records that are not found, are destroyed, and if they are searched for again, we want to make
448
+ # sure to find them. We may want to change this, and provide a separate flag called not_found. In this case you
449
+ # would put these lines here:
450
+ # @attributes = {}
451
+ # sync!
452
+ # and modify server_data_cache so that it does NOT call destroy
453
+
422
454
  @destroyed = true
423
455
 
424
456
  promise
@@ -188,7 +188,11 @@ module ReactiveRecord
188
188
  end
189
189
 
190
190
  def apply_method(method)
191
- method[0] = "find" if method.is_a? Array and method.first == "find_by_id"
191
+ if method.is_a? Array and method.first == "find_by_id"
192
+ method[0] = "find"
193
+ elsif method.is_a? String and method =~ /^\*[0-9]+$/
194
+ method = "*"
195
+ end
192
196
  new_vector = vector + [method]
193
197
  @db_cache.detect { |cached_item| cached_item.vector == new_vector} || build_new_instances(method)
194
198
  end
@@ -196,6 +200,8 @@ module ReactiveRecord
196
200
  def build_new_instances(method)
197
201
  if method == "*all"
198
202
  apply_method_to_cache("*all") { |cache_item| cache_item.value.collect { |record| record.id } }
203
+ elsif method == "*count"
204
+ apply_method_to_cache("*count") { |cache_item| cache_item.value.count }
199
205
  elsif method == "*"
200
206
  if @ar_object and @ar_object.length > 0
201
207
  @ar_object.inject(nil) do | value, record | # just using inject so we will return the last value
@@ -251,36 +257,38 @@ module ReactiveRecord
251
257
  ignore_all = nil
252
258
 
253
259
  # have to process *all before any other items
254
- if sorted_collection = tree.delete("*all")
260
+ # we leave the "*all" key in just for debugging purposes, and then skip it below
261
+
262
+ if sorted_collection = tree["*all"]
255
263
  target.replace sorted_collection.collect { |id| target.proxy_association.klass.find(id) }
256
264
  end
257
265
 
258
266
  tree.each do |method, value|
259
267
  method = JSON.parse(method) rescue method
260
268
  new_target = nil
261
- if !target
269
+ if method == "*all"
270
+ next # its already been processed above
271
+ elsif !target
262
272
  load_from_json(value, Object.const_get(method))
263
- elsif method == "*all"
264
- target.replace value.collect { |id| target.proxy_association.klass.find(id) } unless ignore_all
273
+ elsif method == "*count"
274
+ target.instance_variable_set(:@count, value.first)
265
275
  elsif method.is_a? Integer or method =~ /^[0-9]+$/
266
- ignore_all = true
267
276
  target << (new_target = target.proxy_association.klass.find(method))
268
277
  elsif method.is_a? Array
269
278
  if !(target.class < ActiveRecord::Base)
270
- new_target = target.send *method unless value.is_a? Array # value is an array if scope returns nil
279
+ new_target = target.send *method
280
+ # value is an array if scope returns nil, so we destroy the bogus record
281
+ new_target.destroy and new_target = nil if value.is_a? Array
271
282
  else
272
283
  target.attributes[[method]] = value.first
273
284
  end
274
285
  elsif value.is_a? Array
275
- #target.send "#{method}=", value.first
276
- target.backing_record.reactive_set!(method, value.first)
286
+ target.send "#{method}=", value.first
277
287
  elsif value.is_a? Hash and value[:id] and value[:id].first #and
278
288
  association = target.class.reflect_on_association(method)
279
289
  new_target = association.klass.find(value[:id].first)
280
- #target.send "#{method}=", new_target
281
- target.backing_record.reactive_set!(method, new_target)
290
+ target.send "#{method}=", new_target
282
291
  else
283
- # target might be able to respond to method directly so we can't optimize out the target send
284
292
  new_target = target.send("#{method}=", target.send(method))
285
293
  end
286
294
  load_from_json(value, new_target) if new_target
@@ -1,3 +1,3 @@
1
1
  module ReactiveRecord
2
- VERSION = "0.7.20"
2
+ VERSION = "0.7.22"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reactive-record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.20
4
+ version: 0.7.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitch VanDuyn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-30 00:00:00.000000000 Z
11
+ date: 2015-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails