hyper-model 1.0.alpha1.2 → 1.0.alpha1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.rspec +0 -1
  4. data/Gemfile +6 -5
  5. data/Rakefile +27 -3
  6. data/hyper-model.gemspec +11 -19
  7. data/lib/active_record_base.rb +105 -33
  8. data/lib/enumerable/pluck.rb +3 -2
  9. data/lib/hyper-model.rb +4 -1
  10. data/lib/hyper_model/version.rb +1 -1
  11. data/lib/hyper_react/input_tags.rb +2 -1
  12. data/lib/reactive_record/active_record/associations.rb +130 -34
  13. data/lib/reactive_record/active_record/base.rb +32 -0
  14. data/lib/reactive_record/active_record/class_methods.rb +124 -52
  15. data/lib/reactive_record/active_record/error.rb +2 -0
  16. data/lib/reactive_record/active_record/errors.rb +8 -4
  17. data/lib/reactive_record/active_record/instance_methods.rb +73 -5
  18. data/lib/reactive_record/active_record/public_columns_hash.rb +25 -26
  19. data/lib/reactive_record/active_record/reactive_record/backing_record_inspector.rb +22 -5
  20. data/lib/reactive_record/active_record/reactive_record/base.rb +50 -24
  21. data/lib/reactive_record/active_record/reactive_record/collection.rb +226 -68
  22. data/lib/reactive_record/active_record/reactive_record/dummy_polymorph.rb +22 -0
  23. data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +27 -15
  24. data/lib/reactive_record/active_record/reactive_record/getters.rb +33 -10
  25. data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +81 -51
  26. data/lib/reactive_record/active_record/reactive_record/lookup_tables.rb +5 -5
  27. data/lib/reactive_record/active_record/reactive_record/operations.rb +10 -3
  28. data/lib/reactive_record/active_record/reactive_record/scoped_collection.rb +3 -0
  29. data/lib/reactive_record/active_record/reactive_record/setters.rb +105 -68
  30. data/lib/reactive_record/active_record/reactive_record/while_loading.rb +249 -32
  31. data/lib/reactive_record/broadcast.rb +62 -25
  32. data/lib/reactive_record/interval.rb +3 -3
  33. data/lib/reactive_record/permissions.rb +14 -2
  34. data/lib/reactive_record/scope_description.rb +3 -2
  35. data/lib/reactive_record/server_data_cache.rb +99 -49
  36. data/polymorph-notes.md +143 -0
  37. data/spec_fails.txt +3 -0
  38. metadata +54 -153
  39. data/Gemfile.lock +0 -421
@@ -0,0 +1,143 @@
1
+ ```ruby
2
+ class Picture < ApplicationRecord
3
+ belongs_to :imageable, polymorphic: true
4
+ end
5
+
6
+ class Employee < ApplicationRecord
7
+ has_many :pictures, as: :imageable
8
+ end
9
+
10
+ class Product < ApplicationRecord
11
+ has_many :pictures, as: :imageable
12
+ end
13
+ ```
14
+
15
+ product|employee.pictures -> works almost as normal has_many as far as Hyperstack client is concerned
16
+ imageable is the "alias" of product|employee. Its as if there is a class Imageable that is the superclass
17
+ of Product and Employee.
18
+
19
+ so has_many :pictures means the usual thing (i.e. there is a belongs_to relationship on Picture) its just that
20
+ the belongs_to will be belonging to :imageable instead of :employee or :product.
21
+
22
+ okay fine
23
+
24
+ the other way:
25
+
26
+ the problem is that picture.imageable while loading is pointing to a dummy class (sure call it Imageable)
27
+ so if we say picture.imageable.foo.bar.blat what we get is a dummy value that responds to all methods, and returns itself:
28
+
29
+ picture.imageable -> imageable123 .foo -> imageable123 .bar -> ... etc. but it is a dummy value that will cause a fetch of the actual imageable record (or nil).
30
+
31
+ .imageable should be able to leverage off of server_method.
32
+
33
+ server_method(:imageable, PolymorphicDummy.new(:imageable))
34
+
35
+ hmmmm....
36
+
37
+ really its like doing a picture.imageable.itself (?) (that may work Juuuust fine)
38
+
39
+ so picture.imageable returns this funky dummy value but does an across the wire request for picture.imageable (which should get imageable_id per a normal relationship) and also get picture.imageable_type.
40
+
41
+
42
+ start again....
43
+
44
+ what happens if we ignore (on the client) the polymorphic: and as: keys?
45
+
46
+ belongs_to :imageable
47
+
48
+ means there is a class Imageable, okay so we make one, and add has_many :pictures to it.
49
+
50
+
51
+ and again....
52
+
53
+ ```ruby
54
+ def imageable
55
+ if imageable_type.loaded? && imageable_id.loaded?
56
+ const_get(imageable_type).find(imageable_id)
57
+ else
58
+ DummyImageable.new(self)
59
+ end
60
+ end
61
+ ```
62
+
63
+ very close but will not work for cases like this:
64
+
65
+ ```ruby
66
+ pic = Picture.new
67
+ employee.pictures << pic
68
+ pic.imageable # FAIL... (until its been saved)
69
+ ...
70
+ ```
71
+
72
+ but still it may be as simple as overriding `<<` so that it sets type on imageable. But we still to have a proper belongs to relationship.
73
+
74
+ ```ruby
75
+ def imageable
76
+ if we already have the attribute set
77
+ return the attribute
78
+ else
79
+ set attribute to DummyPolyClass.new(self, 'imageable')
80
+ # DummyPolyClass init will set up a fetch of the actual imageable value
81
+ end
82
+ end
83
+
84
+ def imageable=(x)
85
+ # will it just work ?
86
+ end
87
+ ```
88
+
89
+ its all about the collection inverse. The inverse class of the has_many is the class containing the polymorphic belongs to. But the inverse of a polymorphic belongs to depends on the value. If the value is nil or a DummyPolyClass object then there is no inverse.
90
+
91
+ I think if inverse takes this into account then `<<` and `=` should just "work" (well almost) and probably everything else will to.
92
+
93
+ ### NOTES on the DummyPolyClass...
94
+
95
+ it needs to respond to reflect_on_all_associations, but just return an empty array. This way when we search for matching inverse attribute we won't find it.
96
+
97
+ ### Status
98
+
99
+ added model to inverse, inverse_of, find_inverse
100
+
101
+ if the relationship is a collection then we will always know the inverse.
102
+
103
+ The only time we might no know the inverse is if its NOT a collection (i.e. belongs_to)
104
+
105
+ So only places that are applying inverse to an association that is NOT a collection do we have to pass the model in.
106
+
107
+ All inverse_of method calls have been checked and updated
108
+
109
+ that leaves inverse which is only used in SETTERS hurray!
110
+
111
+
112
+ ### Latest thinking
113
+
114
+ going from `has_many / has_one as: ...` is easy its essentially setting the association foreign_key using the name supplied to the as:
115
+
116
+ The problem is going from the polymorphic belongs_to side.
117
+
118
+ We don't know the actual type we are loading which presents two problems.
119
+
120
+ First we just don't know the type. So if I say `Picture.find(1).imageable.foo.bar` I really can't do anything with foo and bar. This is solved by having a DummyPolymorph class, which responds to all missing methods with itself, and on creation sets up a vector to pull it the id, and type of the record being fetched. This will cause a second fetch to actually get `foo.bar` because we don't know what they are yet. (Its cool beacuse this is like Type inference actually, and I think we could eventually use a type inference system to get rid of the second fetch!!!)
121
+
122
+ Second we don't know the inverse of the relationship (since we don't know the type)
123
+
124
+ We can solve this by aliasing the inverse relationship (the one with the `as: SOMENAME` option) to be `has_many #{__hyperstack_polymorphic_inverse_of_#{SOMENAME}` and then defining method(s) against the relationship name. This way regardless of what the polymorphic relationship points to we know the inverse is `__hyperstack_polymorphic_inverse_of_#{SOMENAME}`.
125
+
126
+ If the inverse relationship is a has_many then we define
127
+ ```ruby
128
+ def #{RELATIONSHIP_NAME}
129
+ __hyperstack_polymorphic_inverse_of_#{SOMENAME}
130
+ end
131
+ ```
132
+
133
+ If the inverse relationship is a has_one we have to work a bit harder:
134
+ ```ruby
135
+ def #{RELATIONSHIP_NAME}
136
+ __hyperstack_polymorphic_inverse_of_#{SOMENAME}[0]
137
+ end
138
+ def #{RELATIONSHIP_NAME}=(x)
139
+ __hyperstack_polymorphic_inverse_of_#{SOMENAME}[0] = x # or perhaps we have to replace the array using the internal method in collection for that purpose.
140
+ end
141
+ ```
142
+
143
+ The remaining problem is that the server side will have no such relationships defined so we need to add the `has_many __hyperstack_polymorphic_inverse_of_#{SOMENAME} as: SOMENAME` server side.
data/spec_fails.txt ADDED
@@ -0,0 +1,3 @@
1
+ rspec ./spec/batch5/save_while_loading_spec.rb:28 # save while loading with push
2
+ rspec ./spec/batch4/default_value_spec.rb:40 # defaultValue special handling will not use the defaultValue param until data is loaded - unit test
3
+ rspec ./spec/batch3/revert_spec.rb:39 # reverting records adds the todo to adam's todos and expects adam to change
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyper-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.alpha1.2
4
+ version: 1.0.alpha1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitch VanDuyn
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-11-16 00:00:00.000000000 Z
12
+ date: 2021-04-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -39,34 +39,20 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: 4.0.0
42
- - !ruby/object:Gem::Dependency
43
- name: hyper-component
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - '='
47
- - !ruby/object:Gem::Version
48
- version: 1.0.alpha1.2
49
- type: :runtime
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - '='
54
- - !ruby/object:Gem::Version
55
- version: 1.0.alpha1.2
56
42
  - !ruby/object:Gem::Dependency
57
43
  name: hyper-operation
58
44
  requirement: !ruby/object:Gem::Requirement
59
45
  requirements:
60
46
  - - '='
61
47
  - !ruby/object:Gem::Version
62
- version: 1.0.alpha1.2
48
+ version: 1.0.alpha1.7
63
49
  type: :runtime
64
50
  prerelease: false
65
51
  version_requirements: !ruby/object:Gem::Requirement
66
52
  requirements:
67
53
  - - '='
68
54
  - !ruby/object:Gem::Version
69
- version: 1.0.alpha1.2
55
+ version: 1.0.alpha1.7
70
56
  - !ruby/object:Gem::Dependency
71
57
  name: bundler
72
58
  requirement: !ruby/object:Gem::Requirement
@@ -82,7 +68,7 @@ dependencies:
82
68
  - !ruby/object:Gem::Version
83
69
  version: '0'
84
70
  - !ruby/object:Gem::Dependency
85
- name: capybara
71
+ name: database_cleaner
86
72
  requirement: !ruby/object:Gem::Requirement
87
73
  requirements:
88
74
  - - ">="
@@ -96,49 +82,49 @@ dependencies:
96
82
  - !ruby/object:Gem::Version
97
83
  version: '0'
98
84
  - !ruby/object:Gem::Dependency
99
- name: chromedriver-helper
85
+ name: factory_bot_rails
100
86
  requirement: !ruby/object:Gem::Requirement
101
87
  requirements:
102
- - - '='
88
+ - - ">="
103
89
  - !ruby/object:Gem::Version
104
- version: 1.2.0
90
+ version: '0'
105
91
  type: :development
106
92
  prerelease: false
107
93
  version_requirements: !ruby/object:Gem::Requirement
108
94
  requirements:
109
- - - '='
95
+ - - ">="
110
96
  - !ruby/object:Gem::Version
111
- version: 1.2.0
97
+ version: '0'
112
98
  - !ruby/object:Gem::Dependency
113
- name: libv8
99
+ name: hyper-spec
114
100
  requirement: !ruby/object:Gem::Requirement
115
101
  requirements:
116
- - - "~>"
102
+ - - '='
117
103
  - !ruby/object:Gem::Version
118
- version: 6.3.0
104
+ version: 1.0.alpha1.7
119
105
  type: :development
120
106
  prerelease: false
121
107
  version_requirements: !ruby/object:Gem::Requirement
122
108
  requirements:
123
- - - "~>"
109
+ - - '='
124
110
  - !ruby/object:Gem::Version
125
- version: 6.3.0
111
+ version: 1.0.alpha1.7
126
112
  - !ruby/object:Gem::Dependency
127
- name: mini_racer
113
+ name: hyper-trace
128
114
  requirement: !ruby/object:Gem::Requirement
129
115
  requirements:
130
- - - "~>"
116
+ - - '='
131
117
  - !ruby/object:Gem::Version
132
- version: 0.1.15
118
+ version: 1.0.alpha1.7
133
119
  type: :development
134
120
  prerelease: false
135
121
  version_requirements: !ruby/object:Gem::Requirement
136
122
  requirements:
137
- - - "~>"
123
+ - - '='
138
124
  - !ruby/object:Gem::Version
139
- version: 0.1.15
125
+ version: 1.0.alpha1.7
140
126
  - !ruby/object:Gem::Dependency
141
- name: selenium-webdriver
127
+ name: mini_racer
142
128
  requirement: !ruby/object:Gem::Requirement
143
129
  requirements:
144
130
  - - ">="
@@ -152,7 +138,7 @@ dependencies:
152
138
  - !ruby/object:Gem::Version
153
139
  version: '0'
154
140
  - !ruby/object:Gem::Dependency
155
- name: database_cleaner
141
+ name: pg
156
142
  requirement: !ruby/object:Gem::Requirement
157
143
  requirements:
158
144
  - - ">="
@@ -166,91 +152,27 @@ dependencies:
166
152
  - !ruby/object:Gem::Version
167
153
  version: '0'
168
154
  - !ruby/object:Gem::Dependency
169
- name: factory_bot_rails
155
+ name: opal-rails
170
156
  requirement: !ruby/object:Gem::Requirement
171
157
  requirements:
172
158
  - - ">="
173
159
  - !ruby/object:Gem::Version
174
- version: '0'
175
- type: :development
176
- prerelease: false
177
- version_requirements: !ruby/object:Gem::Requirement
178
- requirements:
179
- - - ">="
180
- - !ruby/object:Gem::Version
181
- version: '0'
182
- - !ruby/object:Gem::Dependency
183
- name: mysql2
184
- requirement: !ruby/object:Gem::Requirement
185
- requirements:
186
- - - ">="
160
+ version: 0.9.4
161
+ - - "<"
187
162
  - !ruby/object:Gem::Version
188
- version: '0'
163
+ version: '2.0'
189
164
  type: :development
190
165
  prerelease: false
191
166
  version_requirements: !ruby/object:Gem::Requirement
192
167
  requirements:
193
168
  - - ">="
194
- - !ruby/object:Gem::Version
195
- version: '0'
196
- - !ruby/object:Gem::Dependency
197
- name: opal-activesupport
198
- requirement: !ruby/object:Gem::Requirement
199
- requirements:
200
- - - "~>"
201
- - !ruby/object:Gem::Version
202
- version: 0.3.1
203
- type: :development
204
- prerelease: false
205
- version_requirements: !ruby/object:Gem::Requirement
206
- requirements:
207
- - - "~>"
208
- - !ruby/object:Gem::Version
209
- version: 0.3.1
210
- - !ruby/object:Gem::Dependency
211
- name: opal-browser
212
- requirement: !ruby/object:Gem::Requirement
213
- requirements:
214
- - - "~>"
215
- - !ruby/object:Gem::Version
216
- version: 0.2.0
217
- type: :development
218
- prerelease: false
219
- version_requirements: !ruby/object:Gem::Requirement
220
- requirements:
221
- - - "~>"
222
- - !ruby/object:Gem::Version
223
- version: 0.2.0
224
- - !ruby/object:Gem::Dependency
225
- name: opal-rails
226
- requirement: !ruby/object:Gem::Requirement
227
- requirements:
228
- - - "~>"
229
- - !ruby/object:Gem::Version
230
- version: 0.9.4
231
- type: :development
232
- prerelease: false
233
- version_requirements: !ruby/object:Gem::Requirement
234
- requirements:
235
- - - "~>"
236
169
  - !ruby/object:Gem::Version
237
170
  version: 0.9.4
238
- - !ruby/object:Gem::Dependency
239
- name: parser
240
- requirement: !ruby/object:Gem::Requirement
241
- requirements:
242
- - - ">="
243
- - !ruby/object:Gem::Version
244
- version: '0'
245
- type: :development
246
- prerelease: false
247
- version_requirements: !ruby/object:Gem::Requirement
248
- requirements:
249
- - - ">="
171
+ - - "<"
250
172
  - !ruby/object:Gem::Version
251
- version: '0'
173
+ version: '2.0'
252
174
  - !ruby/object:Gem::Dependency
253
- name: pry
175
+ name: pry-rescue
254
176
  requirement: !ruby/object:Gem::Requirement
255
177
  requirements:
256
178
  - - ">="
@@ -264,7 +186,7 @@ dependencies:
264
186
  - !ruby/object:Gem::Version
265
187
  version: '0'
266
188
  - !ruby/object:Gem::Dependency
267
- name: pry-rescue
189
+ name: pry-stack_explorer
268
190
  requirement: !ruby/object:Gem::Requirement
269
191
  requirements:
270
192
  - - ">="
@@ -325,14 +247,20 @@ dependencies:
325
247
  requirements:
326
248
  - - ">="
327
249
  - !ruby/object:Gem::Version
328
- version: 4.0.0
250
+ version: 5.0.0
251
+ - - "<"
252
+ - !ruby/object:Gem::Version
253
+ version: '7.0'
329
254
  type: :development
330
255
  prerelease: false
331
256
  version_requirements: !ruby/object:Gem::Requirement
332
257
  requirements:
333
258
  - - ">="
334
259
  - !ruby/object:Gem::Version
335
- version: 4.0.0
260
+ version: 5.0.0
261
+ - - "<"
262
+ - !ruby/object:Gem::Version
263
+ version: '7.0'
336
264
  - !ruby/object:Gem::Dependency
337
265
  name: rake
338
266
  requirement: !ruby/object:Gem::Requirement
@@ -367,20 +295,6 @@ dependencies:
367
295
  - - "<"
368
296
  - !ruby/object:Gem::Version
369
297
  version: 2.5.0
370
- - !ruby/object:Gem::Dependency
371
- name: reactrb-rails-generator
372
- requirement: !ruby/object:Gem::Requirement
373
- requirements:
374
- - - ">="
375
- - !ruby/object:Gem::Version
376
- version: '0'
377
- type: :development
378
- prerelease: false
379
- version_requirements: !ruby/object:Gem::Requirement
380
- requirements:
381
- - - ">="
382
- - !ruby/object:Gem::Version
383
- version: '0'
384
298
  - !ruby/object:Gem::Dependency
385
299
  name: rspec-collection_matchers
386
300
  requirement: !ruby/object:Gem::Requirement
@@ -483,16 +397,16 @@ dependencies:
483
397
  name: rubocop
484
398
  requirement: !ruby/object:Gem::Requirement
485
399
  requirements:
486
- - - "~>"
400
+ - - ">="
487
401
  - !ruby/object:Gem::Version
488
- version: 0.51.0
402
+ version: '0'
489
403
  type: :development
490
404
  prerelease: false
491
405
  version_requirements: !ruby/object:Gem::Requirement
492
406
  requirements:
493
- - - "~>"
407
+ - - ">="
494
408
  - !ruby/object:Gem::Version
495
- version: 0.51.0
409
+ version: '0'
496
410
  - !ruby/object:Gem::Dependency
497
411
  name: shoulda
498
412
  requirement: !ruby/object:Gem::Requirement
@@ -525,30 +439,30 @@ dependencies:
525
439
  name: spring-commands-rspec
526
440
  requirement: !ruby/object:Gem::Requirement
527
441
  requirements:
528
- - - ">="
442
+ - - "~>"
529
443
  - !ruby/object:Gem::Version
530
- version: '0'
444
+ version: 1.0.4
531
445
  type: :development
532
446
  prerelease: false
533
447
  version_requirements: !ruby/object:Gem::Requirement
534
448
  requirements:
535
- - - ">="
449
+ - - "~>"
536
450
  - !ruby/object:Gem::Version
537
- version: '0'
451
+ version: 1.0.4
538
452
  - !ruby/object:Gem::Dependency
539
453
  name: sqlite3
540
454
  requirement: !ruby/object:Gem::Requirement
541
455
  requirements:
542
- - - ">="
456
+ - - "~>"
543
457
  - !ruby/object:Gem::Version
544
- version: '0'
458
+ version: 1.4.2
545
459
  type: :development
546
460
  prerelease: false
547
461
  version_requirements: !ruby/object:Gem::Requirement
548
462
  requirements:
549
- - - ">="
463
+ - - "~>"
550
464
  - !ruby/object:Gem::Version
551
- version: '0'
465
+ version: 1.4.2
552
466
  - !ruby/object:Gem::Dependency
553
467
  name: timecop
554
468
  requirement: !ruby/object:Gem::Requirement
@@ -563,20 +477,6 @@ dependencies:
563
477
  - - "~>"
564
478
  - !ruby/object:Gem::Version
565
479
  version: 0.8.1
566
- - !ruby/object:Gem::Dependency
567
- name: unparser
568
- requirement: !ruby/object:Gem::Requirement
569
- requirements:
570
- - - ">="
571
- - !ruby/object:Gem::Version
572
- version: '0'
573
- type: :development
574
- prerelease: false
575
- version_requirements: !ruby/object:Gem::Requirement
576
- requirements:
577
- - - ">="
578
- - !ruby/object:Gem::Version
579
- version: '0'
580
480
  description: HyperModel gives your HyperComponents CRUD access to your ActiveRecord
581
481
  models on the client, using the the standard ActiveRecord API. HyperModel also implements
582
482
  push notifications (via a number of possible technologies) so changes to records
@@ -592,7 +492,6 @@ files:
592
492
  - ".rspec"
593
493
  - ".travis.yml"
594
494
  - Gemfile
595
- - Gemfile.lock
596
495
  - Rakefile
597
496
  - bin/console
598
497
  - bin/setup
@@ -623,6 +522,7 @@ files:
623
522
  - lib/reactive_record/active_record/reactive_record/base.rb
624
523
  - lib/reactive_record/active_record/reactive_record/collection.rb
625
524
  - lib/reactive_record/active_record/reactive_record/column_types.rb
525
+ - lib/reactive_record/active_record/reactive_record/dummy_polymorph.rb
626
526
  - lib/reactive_record/active_record/reactive_record/dummy_value.rb
627
527
  - lib/reactive_record/active_record/reactive_record/getters.rb
628
528
  - lib/reactive_record/active_record/reactive_record/isomorphic_base.rb
@@ -642,6 +542,8 @@ files:
642
542
  - lib/reactive_record/scope_description.rb
643
543
  - lib/reactive_record/serializers.rb
644
544
  - lib/reactive_record/server_data_cache.rb
545
+ - polymorph-notes.md
546
+ - spec_fails.txt
645
547
  homepage: http://ruby-hyperstack.org
646
548
  licenses:
647
549
  - MIT
@@ -661,8 +563,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
661
563
  - !ruby/object:Gem::Version
662
564
  version: 1.3.1
663
565
  requirements: []
664
- rubyforge_project:
665
- rubygems_version: 2.7.8
566
+ rubygems_version: 3.0.8
666
567
  signing_key:
667
568
  specification_version: 4
668
569
  summary: React based CRUD access and Synchronization of active record models across