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

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 (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