passive_record 0.4.14 → 0.4.15

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cacd9ce096b75a0cb189db566c1b506263462bcd
4
- data.tar.gz: 6d05d9c4520b4f8a7365ff587ee72e49fcb93f37
3
+ metadata.gz: 2e72e0564a1b8661c945d597f7419a24c9b00eb8
4
+ data.tar.gz: 1ff3f8c8430a145d19d6ea2c7c17e69a067a15b1
5
5
  SHA512:
6
- metadata.gz: 56634dcfa1edfa95df038ace1d9ea482b95a3d4766961dd802955cbd35f37311a3b97d2d97f93fc255fdafd248ce7dbae7fa867de964f4a6f2dfa950fd24331f
7
- data.tar.gz: 7aa8cec6e8442a4e9c7eb7a2cf1a72acd686028577b9604ef9ee373977a7deda2d8c3673fb6a9303eaaea713f0eae3289d18f06761afabd34d6cdbaf5bea6ba2
6
+ metadata.gz: 7f0fabaab580b4b110f49b16367f945180e8da5c5228d151caae2eb1bdbe9c85e8f85b2aab3d44fcb6136ac062d4a41d0e12f5699059b2b421484b14c1a30acd
7
+ data.tar.gz: 4d5cc36aa5a22c8a6573f7e653c5cfdfff04668ed3f150277f33546de1c3936bdab49e02886bdf979e63ca34e825c67c7363fffc834acb42dbfddb9086c12ffe
data/README.md CHANGED
@@ -44,6 +44,7 @@ PassiveRecord may be right for you!
44
44
  end
45
45
 
46
46
  class Dog < Model
47
+ attr_accessor :breed
47
48
  belongs_to :child
48
49
  end
49
50
 
@@ -64,26 +65,25 @@ PassiveRecord may be right for you!
64
65
  child = parent.create_child
65
66
  => Child (id: 1, dog_id: nil, parent_id: 1)
66
67
 
67
- dog = child.create_dog
68
- => Dog (id: 1, child_id: 1)
68
+ dog = child.create_dog(breed: "Pug")
69
+ => Dog (id: 1, child_id: 1, breed: "Pug")
69
70
 
70
71
  # Inverse relationships
71
72
  dog.child
72
- => Child (id: 1, dog_id: 1, parent_id: 1)
73
73
 
74
74
  Dog.find_by child: child
75
- => Dog (id: 1, child_id: 1)
75
+ => Dog (id: 1, child_id: 1, breed: "Pug")
76
76
 
77
77
  # Has many through
78
78
  parent.dogs
79
79
  => [ ...has_many :through relation... ]
80
80
 
81
81
  parent.dogs.all
82
- => [Dog (id: 1, child_id: 1)]
82
+ => [Dog (id: 1, child_id: 1, breed: "Pug")]
83
83
 
84
84
  # Nested queries
85
85
  Dog.find_all_by(child: { parent: parent })
86
- => [Dog (id: 1, child_id: 1)]
86
+ => [Dog (id: 1, child_id: 1, breed: "Pug")]
87
87
  ````
88
88
 
89
89
  ## PassiveRecord API
@@ -32,7 +32,7 @@ module PassiveRecord
32
32
  end
33
33
 
34
34
  define_method(parent_name_sym) do
35
- relation = relata.detect { |rel| rel.association == association }
35
+ relation = detect_relation(association)
36
36
  association.parent_class.find(relation.parent_model_id)
37
37
  end
38
38
 
@@ -41,7 +41,7 @@ module PassiveRecord
41
41
  end
42
42
 
43
43
  define_method(:"#{parent_name_sym}_id=") do |new_parent_id|
44
- relation = relata.detect { |rel| rel.association == association }
44
+ relation = detect_relation(association)
45
45
  relation.parent_model_id = new_parent_id
46
46
  end
47
47
  end
@@ -57,12 +57,12 @@ module PassiveRecord
57
57
  end
58
58
 
59
59
  define_method(child_name_sym) do
60
- relation = relata.detect { |rel| rel.association == association }
60
+ relation = detect_relation(association)
61
61
  relation.lookup
62
62
  end
63
63
 
64
64
  define_method(:"create_#{child_name_sym}") do |attrs={}|
65
- relation = relata.detect { |rel| rel.association == association }
65
+ relation = detect_relation(association)
66
66
  relation.create(attrs)
67
67
  end
68
68
 
@@ -71,7 +71,7 @@ module PassiveRecord
71
71
  end
72
72
 
73
73
  define_method(:"#{child_name_sym}_id=") do |new_child_id|
74
- relation = relata.detect { |rel| rel.association == association }
74
+ relation = detect_relation(association) #relata.detect { |rel| rel.association == association }
75
75
  rel = relation.lookup
76
76
  rel && rel.send(:"#{relation.parent_model_id_field}=", nil)
77
77
 
@@ -102,7 +102,7 @@ module PassiveRecord
102
102
  end
103
103
 
104
104
  define_method(:"#{collection_name_sym.to_s.singularize}_ids=") do |new_collection_ids|
105
- relation = relata.detect { |rel| rel.association == association }
105
+ relation = detect_relation(association) # relata.detect { |rel| rel.association == association }
106
106
 
107
107
  intermediary = relation.intermediary_relation
108
108
 
@@ -113,16 +113,16 @@ module PassiveRecord
113
113
 
114
114
  # add in new ones...
115
115
  singular_target = collection_name_sym.to_s.singularize
116
- if !(relation.nested_association.is_a?(BelongsToAssociation))# &&
116
+ if !(relation.nested_association.is_a?(BelongsToAssociation))
117
117
  intermediary.create(
118
118
  singular_target + "_ids" => new_collection_ids,
119
- relation.parent_model_id_field => relation.id
119
+ relation.parent_model_id_field => relation.id
120
120
  )
121
121
  else
122
122
  new_collection_ids.each do |child_id|
123
123
  intermediary.create(
124
- singular_target + "_id" => child_id,
125
- relation.parent_model_id_field => relation.id
124
+ singular_target + "_id" => child_id,
125
+ relation.parent_model_id_field => relation.id
126
126
  )
127
127
  end
128
128
  end
@@ -132,7 +132,7 @@ module PassiveRecord
132
132
  associate!(association)
133
133
 
134
134
  define_method(:"#{collection_name_sym}=") do |new_collection|
135
- relation = relata.detect { |rel| rel.association == association }
135
+ relation = detect_relation(association)
136
136
 
137
137
  # detach existing children...
138
138
  relation.all.each do |child|
@@ -146,21 +146,26 @@ module PassiveRecord
146
146
  end
147
147
 
148
148
  define_method(:"#{collection_name_sym.to_s.singularize}_ids=") do |new_collection_ids|
149
- relation = relata.detect { |rel| rel.association == association }
149
+ relation = detect_relation(association) #@ relata.detect { |rel| rel.association == association }
150
150
  send(:"#{collection_name_sym}=", relation.child_class.find(new_collection_ids))
151
151
  end
152
152
  end
153
153
 
154
154
  define_method(collection_name_sym) do
155
- relata.detect { |rel| rel.association == association }
155
+ detect_relation(association)
156
+ # relata.detect { |rel| rel.association == association }
156
157
  end
157
158
 
158
159
  define_method(:"#{collection_name_sym.to_s.singularize}_ids") do
159
- send(collection_name_sym).map(&:id)
160
+ begin
161
+ send(collection_name_sym).map(&:id)
162
+ rescue
163
+ binding.pry
164
+ end
160
165
  end
161
166
 
162
167
  define_method(:"create_#{collection_name_sym.to_s.singularize}") do |attrs={}|
163
- relation = relata.detect { |rel| rel.association == association }
168
+ relation = detect_relation(association) # relata.detect { |rel| rel.association == association }
164
169
  relation.create(attrs)
165
170
  end
166
171
  end
@@ -6,9 +6,11 @@ module PassiveRecord
6
6
  end
7
7
 
8
8
  def parent_class
9
- module_name = child_class.name.deconstantize
10
- module_name = "Object" if module_name.empty?
11
- (module_name.constantize).const_get(parent_class_name)
9
+ @parent_class ||= (
10
+ module_name = child_class.name.deconstantize
11
+ module_name = "Object" if module_name.empty?
12
+ (module_name.constantize).const_get(parent_class_name)
13
+ )
12
14
  end
13
15
 
14
16
  def child_class_name
@@ -4,11 +4,6 @@ module PassiveRecord
4
4
  def to_relation(parent_model)
5
5
  HasManyThroughRelation.new(self, parent_model)
6
6
  end
7
-
8
- def nested_association
9
- thru_klass = base_association.child_class_name.singularize.constantize
10
- thru_klass.associations.detect { |assn| assn.child_class_name == child_class_name }
11
- end
12
7
  end
13
8
 
14
9
  class HasManyThroughRelation < HasManyRelation
@@ -69,9 +64,9 @@ module PassiveRecord
69
64
  if intermediate_results && !join_results.empty?
70
65
  final_results = join_results.flat_map(&nested_association.target_name_symbol)
71
66
  if final_results.first.is_a?(Associations::Relation)
72
- final_results.flat_map(&:all)
67
+ final_results.flat_map(&:all).compact
73
68
  else
74
- Array(final_results)
69
+ Array(final_results.compact)
75
70
  end
76
71
  else
77
72
  []
@@ -90,61 +85,13 @@ module PassiveRecord
90
85
  end
91
86
  end
92
87
 
93
- def intermediary_conditions
94
- if intermediary_relation.is_a?(HasManyThroughRelation)
95
- conds = intermediary_relation.intermediary_conditions
96
-
97
- if nested_association.habtm || nested_association.is_a?(HasManyThroughAssociation)
98
- { association.through_class => conds }
99
- else
100
- { association.through_class.to_s.singularize.to_sym => conds }
101
- end
102
- elsif intermediary_relation.association.is_a?(HasManyAssociation) # normal has many?
103
- intermediary_key = if association.is_a?(HasManyThroughAssociation)
104
- ch = association.child_class_name.constantize
105
- inverse_assn = ch.associations.detect { |assn|
106
- if assn.is_a?(HasManyAssociation) || assn.is_a?(HasManyThroughAssociation)
107
- assn.child_class_name == association.base_association.child_class_name
108
- else # belongs to...
109
- assn.parent_class_name == association.base_association.child_class_name
110
- end
111
- }
112
-
113
- if inverse_assn.nil?
114
- association.through_class.to_s.singularize.to_sym
115
- elsif inverse_assn.is_a?(HasManyAssociation) || inverse_assn.is_a?(HasManyThroughAssociation)
116
- inverse_assn.children_name_sym
117
- else
118
- inverse_assn.target_name_symbol
119
- end
120
- elsif association.habtm
121
- association.base_association.children_name_sym
122
- else
123
- association.base_association.children_name_sym.to_s.singularize.to_sym
124
- end
125
-
126
- nested_conds = { intermediary_key => { parent_model_id_field.to_sym => parent_model.id } }
127
-
128
- if nested_association.is_a?(HasManyThroughAssociation)
129
- n = nested_association
130
- hash = nested_conds
131
-
132
- until !n.is_a?(HasManyThroughAssociation)
133
- key = n.through_class.to_s.singularize.to_sym
134
- hash = {key => hash}
135
- n = n.nested_association
136
- end
137
-
138
- hash
139
- else
140
- nested_conds
141
- end
142
- end
143
- end
144
-
145
88
  def where(conditions={})
146
- merged_conditions = conditions.merge(intermediary_conditions)
147
- child_class.where(merged_conditions)
89
+ Core::HasManyThroughQuery.new(
90
+ child_class,
91
+ parent_model,
92
+ association.target_name_symbol,
93
+ conditions
94
+ )
148
95
  end
149
96
  end
150
97
  end
@@ -40,9 +40,11 @@ module PassiveRecord
40
40
  end
41
41
 
42
42
  def child_class
43
- module_name = association.parent_class.name.deconstantize
44
- module_name = "Object" if module_name.empty?
45
- (module_name.constantize).const_get(association.child_class_name.singularize)
43
+ @child_class ||= (
44
+ module_name = association.parent_class.name.deconstantize
45
+ module_name = "Object" if module_name.empty?
46
+ (module_name.constantize).const_get(association.child_class_name.singularize)
47
+ )
46
48
  end
47
49
 
48
50
  def id
@@ -25,26 +25,30 @@ module PassiveRecord
25
25
  if @scope
26
26
  matching = @scope.method(:matching_instances)
27
27
  if negated?
28
- @klass.reject(&matching)
28
+ raw_all.reject(&matching)
29
29
  else
30
- @klass.select(&matching)
30
+ raw_all.select(&matching)
31
31
  end
32
32
  else
33
33
  matching = method(:matching_instances)
34
- @klass.select(&matching)
34
+ raw_all.select(&matching)
35
35
  end
36
36
  end
37
37
  def_delegators :all, :sample
38
38
 
39
+ def raw_all
40
+ @klass.all
41
+ end
42
+
39
43
  def each
40
44
  if @scope
41
45
  matching = @scope.method(:matching_instances)
42
46
  if negated?
43
- @klass.all.each do |instance|
47
+ raw_all.each do |instance|
44
48
  yield instance unless matching[instance]
45
49
  end
46
50
  else
47
- @klass.all.each do |instance|
51
+ raw_all.each do |instance|
48
52
  yield instance if matching[instance]
49
53
  end
50
54
  end
@@ -182,5 +186,18 @@ module PassiveRecord
182
186
  true
183
187
  end
184
188
  end
189
+
190
+ class HasManyThroughQuery < Query
191
+ def initialize(klass, instance, target_name_sym, conditions={})
192
+ @klass = klass
193
+ @instance = instance
194
+ @target_name_sym = target_name_sym
195
+ @conditions = conditions
196
+ end
197
+
198
+ def raw_all
199
+ @instance.send(@target_name_sym).all
200
+ end
201
+ end
185
202
  end
186
203
  end
@@ -52,6 +52,13 @@ module PassiveRecord
52
52
  []
53
53
  end
54
54
 
55
+ def detect_relation(assn)
56
+ @_associations ||= {}
57
+ @_associations[assn] ||= (
58
+ relata.detect { |rel| rel.association == assn }
59
+ )
60
+ end
61
+
55
62
  private
56
63
 
57
64
  def relata
@@ -1,4 +1,4 @@
1
1
  module PassiveRecord
2
2
  # passive_record version
3
- VERSION = "0.4.14"
3
+ VERSION = "0.4.15"
4
4
  end
@@ -288,64 +288,124 @@ describe "passive record models" do
288
288
  end
289
289
 
290
290
  context 'querying with scopes through relationships' do
291
- let!(:network) { Network.create }
292
- let!(:stream) { network.create_stream }
293
- let!(:channel) { stream.create_channel }
294
- let!(:feed) { channel.create_feed }
295
- let!(:a_blog) { feed.create_blog }
291
+ let(:network) { Network.create }
292
+ let(:stream) { network.create_stream }
293
+ let(:channel) { stream.create_channel }
294
+ let(:feed) { channel.create_feed }
295
+ let(:a_blog) { feed.create_blog }
296
+
296
297
  let!(:not_recent_post) { a_blog.create_post(published_at: 10.days.ago) }
297
298
  let!(:recent_post) do
298
299
  a_blog.create_post(published_at: 1.day.ago)
299
300
  end
300
301
 
302
+ let!(:special_category) { recent_post.create_category(special: true) }
303
+ let!(:unspecial_category) { recent_post.create_category(special: false) }
304
+
305
+ let!(:approved_comment) { recent_post.create_comment(approved: true) }
306
+ let!(:unapproved_comment) { recent_post.create_comment(approved: false) }
307
+
308
+ ###
309
+ #
310
+ let(:another_network) { Network.create }
311
+ let(:another_stream) { another_network.create_stream }
312
+ let(:another_channel) { another_stream.create_channel }
313
+ let(:another_feed) { another_channel.create_feed }
314
+ let(:another_blog) { another_feed.create_blog }
315
+
316
+
317
+ let!(:post_from_unrelated_blog) { another_blog.create_post(published_at: 1.day.ago) }
318
+ let!(:unrelated_comment) do
319
+ post_from_unrelated_blog.create_comment(approved: true)
320
+ end
321
+
322
+ let!(:another_category) do
323
+ post_from_unrelated_blog.create_category(special: true)
324
+ end
325
+
301
326
  describe 'should find related models through a has many' do
302
- it 'should restrict' do
327
+ it 'should refine' do
303
328
  expect(a_blog.posts.recent).to include(recent_post)
304
329
  expect(a_blog.posts.recent).not_to include(not_recent_post)
305
330
  end
331
+
332
+ it 'should restrict' do
333
+ a_blog.posts.all.each do |post|
334
+ expect(another_blog.posts.all.map(&:id)).not_to include(post.id)
335
+ end
336
+ end
306
337
  end
307
338
 
308
339
  describe 'should find related models on a has_many through' do
309
- it 'should restrict' do
340
+ it 'should refine' do
310
341
  expect(feed.posts.recent).to include(recent_post)
311
342
  expect(feed.posts.recent).not_to include(not_recent_post)
312
343
  end
344
+
345
+ it 'should restrict' do
346
+ feed.posts.each do |post|
347
+ expect(another_feed.posts).not_to include(post)
348
+ end
349
+ end
313
350
  end
314
351
 
315
352
  describe 'should find related models on a nested has_many thru' do
316
- it 'should restrict' do
353
+ it 'should refine' do
317
354
  expect(channel.posts.recent).to include(recent_post)
318
355
  expect(channel.posts.recent).not_to include(not_recent_post)
319
356
  end
357
+
358
+ it 'should restrict' do
359
+ channel.posts.each do |post|
360
+ expect(another_channel.posts).not_to include(post)
361
+ end
362
+ end
320
363
  end
321
364
 
322
365
  describe 'should find related models on a double-nested has_many thru' do
323
- it 'should restrict' do
366
+ it 'should refine' do
324
367
  expect(stream.posts.recent).to include(recent_post)
325
368
  expect(stream.posts.recent).not_to include(not_recent_post)
326
369
  end
370
+
371
+ it 'should restrict' do
372
+ expect(stream.posts.all).not_to be_empty
373
+ stream.posts.all.each do |post|
374
+ expect(another_stream.posts.all).not_to include(post)
375
+ end
376
+ end
327
377
  end
328
378
 
329
379
  describe 'should find related models on a deeply nested has_many thru' do
330
- it 'should restrict' do
380
+ it 'should refine' do
331
381
  expect(network.posts.recent).to include(recent_post)
332
382
  expect(network.posts.recent).not_to include(not_recent_post)
333
383
  end
384
+
385
+ it 'should restrict' do
386
+ network.posts.all.each do |post|
387
+ expect(another_network.posts.all.map(&:id)).not_to include(post.id)
388
+ end
389
+ end
334
390
  end
335
391
 
336
392
  describe 'should find related models on a recursive has_many thru' do
337
- let!(:approved_comment) { Post.first.create_comment(approved: true) }
338
- let!(:unapproved_comment) { Post.last.create_comment(approved: false) }
339
-
340
- it 'should refine/restrict' do
393
+ it 'should refine' do
341
394
  expect(network.comments.approved).to include(approved_comment)
342
395
  expect(network.comments.approved).not_to include(unapproved_comment)
343
396
  end
397
+
398
+ it 'should restrict' do
399
+ expect(network.comments.all).not_to be_empty
400
+ network.comments.all.each do |comment|
401
+ expect(another_network.comments).not_to include(comment)
402
+ end
403
+ end
344
404
  end
345
405
 
346
406
  describe 'should find related models a recursive has_many :thru a habtm' do
347
- let!(:promoted_tag) { Post.first.create_tag(promoted: true) }
348
- let!(:unpromoted_tag) { Post.last.create_tag(promoted: false) }
407
+ let!(:promoted_tag) { recent_post.create_tag(promoted: true) }
408
+ let!(:unpromoted_tag) { recent_post.create_tag(promoted: false) }
349
409
 
350
410
  it 'should refine and restrict' do
351
411
  expect(network.tags.promoted).to include(promoted_tag)
@@ -354,13 +414,19 @@ describe "passive record models" do
354
414
  end
355
415
 
356
416
  describe 'should find related nested models through a manual habtm' do
357
- let!(:special_category) { Post.first.create_category(special: true) }
358
- let!(:unspecial_category) { Post.last.create_category(special: false) }
359
417
 
360
- it 'should refine and restrict' do
418
+ it 'should refine' do
361
419
  expect(network.categories.special).to include(special_category)
362
420
  expect(network.categories.special).not_to include(unspecial_category)
363
421
  end
422
+
423
+ it 'should restrict' do
424
+ expect(another_network.categories.all).not_to be_empty
425
+ expect(network.categories.all).not_to be_empty
426
+ another_network.categories.where.all.each do |category|
427
+ expect(network.categories.where.all).not_to include(category)
428
+ end
429
+ end
364
430
  end
365
431
  end
366
432
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passive_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.14
4
+ version: 0.4.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Weissman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-19 00:00:00.000000000 Z
11
+ date: 2016-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport