Skip to content

Commit 6eec996

Browse files
author
Lee Richmond
committed
Allow recursive sideloading
This allows things like ?include=children.children.children To have the correct namespace, so ?filter[children.children][name]=foo will work
1 parent b0ab12d commit 6eec996

File tree

7 files changed

+49
-9
lines changed

7 files changed

+49
-9
lines changed

lib/jsonapi_compliable.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
require "jsonapi_compliable/util/relationship_payload"
2323
require "jsonapi_compliable/util/persistence"
2424
require "jsonapi_compliable/util/validation_response"
25+
require "jsonapi_compliable/util/sideload"
2526

2627
# require correct jsonapi-rb before extensions
2728
if defined?(Rails)

lib/jsonapi_compliable/query.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,11 @@ def association?(name)
173173
end
174174

175175
def parse_include(memo, incl_hash, namespace)
176+
memo[namespace] ||= self.class.default_hash
176177
memo[namespace].merge!(include: incl_hash)
177178

178179
incl_hash.each_pair do |key, sub_hash|
180+
key = Util::Sideload.namespace(namespace, key)
179181
memo.merge!(parse_include(memo, sub_hash, key))
180182
end
181183

lib/jsonapi_compliable/scope.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ def sideload(results, includes)
8181

8282
includes.each_pair do |name, nested|
8383
sideload = @resource.sideload(name)
84-
sideload.resolve(results, @query)
84+
namespace = Util::Sideload.namespace(@namespace, sideload.name)
85+
sideload.resolve(results, @query, namespace)
8586
end
8687
end
8788

lib/jsonapi_compliable/sideload.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,7 @@ def group_by(grouping_field)
264264
# @see Resource#with_context
265265
# @return [void]
266266
# @api private
267-
def resolve(parents, query, namespace = nil)
268-
namespace ||= name
269-
267+
def resolve(parents, query, namespace)
270268
if polymorphic?
271269
resolve_polymorphic(parents, query)
272270
else
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module JsonapiCompliable
2+
module Util
3+
# @api private
4+
class Sideload
5+
# Determine the namespace for the sideload
6+
#
7+
# In other words, given a query like
8+
# /things?include=a.b
9+
#
10+
# When 'a' is sideloading 'b', b's namespace is 'b'.
11+
#
12+
# However, consider a recursive tree structure:
13+
#
14+
# /things?include=children.children
15+
#
16+
# The first occurrance of "children" will have the namespace
17+
# "children", the second will be "children.children" and so forth.
18+
#
19+
# This is used to match up other criteria in the query:
20+
#
21+
# ?filter[children.children][a]=b
22+
#
23+
# @api private
24+
def self.namespace(a, b)
25+
if a.to_s.split('.')[0] == b.to_s
26+
:"#{a}.#{b}"
27+
else
28+
b
29+
end
30+
end
31+
end
32+
end
33+
end

spec/scope_spec.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
end
2525

2626
context 'when sideloading' do
27-
let(:sideload) { double }
27+
let(:sideload) { double(name: :books) }
2828
let(:results) { double }
2929

3030
before do
@@ -40,10 +40,15 @@
4040
end
4141

4242
it 'resolves the sideload' do
43-
expect(sideload).to receive(:resolve).with(results, query)
43+
expect(sideload).to receive(:resolve).with(results, query, sideload.name)
4444
instance.resolve
4545
end
4646

47+
context 'and it is nested within the same namespace' do
48+
xit 'resolves with the correct namespace' do
49+
end
50+
end
51+
4752
context 'but no parents were found' do
4853
let(:results) { [] }
4954

spec/sideload_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def foo
6666
end
6767

6868
it 'groups parents, then resolves that group' do
69-
instance.resolve(parents, query)
69+
instance.resolve(parents, query, instance.name)
7070
expect(parents.first[:child]).to eq({ parent_id: 1 })
7171
end
7272
end
@@ -96,11 +96,11 @@ def foo
9696
expect(JsonapiCompliable::Scope).to receive(:new)
9797
.with(base_scope, anything, query, default_paginate: false, namespace: :foo)
9898
.and_return(scope)
99-
instance.resolve(parents, query)
99+
instance.resolve(parents, query, instance.name)
100100
end
101101

102102
it 'assigns results to parents' do
103-
instance.resolve(parents, query)
103+
instance.resolve(parents, query, instance.name)
104104
expect(parents.first[:child]).to eq({ parent_id: 1 })
105105
end
106106

0 commit comments

Comments
 (0)