Skip to content

Commit 30b6e9b

Browse files
committed
Change name from linkage to always_include_resource_ids, add option on sideload to override default, split out tests into own file
1 parent b1cc83e commit 30b6e9b

File tree

5 files changed

+297
-213
lines changed

5 files changed

+297
-213
lines changed

lib/graphiti/sideload.rb

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,31 @@ class Sideload
1818
:link_proc
1919

2020
def initialize(name, opts)
21-
@name = name
21+
@name = name
2222
validate_options!(opts)
23-
@parent_resource_class = opts[:parent_resource]
24-
@resource_class = opts[:resource]
25-
@primary_key = opts[:primary_key]
26-
@foreign_key = opts[:foreign_key]
27-
@type = opts[:type]
28-
@base_scope = opts[:base_scope]
29-
@readable = opts[:readable]
30-
@writable = opts[:writable]
31-
@as = opts[:as]
32-
@link = opts[:link]
33-
@single = opts[:single]
34-
@remote = opts[:remote]
23+
@parent_resource_class = opts[:parent_resource]
24+
@resource_class = opts[:resource]
25+
@primary_key = opts[:primary_key]
26+
@foreign_key = opts[:foreign_key]
27+
@type = opts[:type]
28+
@base_scope = opts[:base_scope]
29+
@readable = opts[:readable]
30+
@writable = opts[:writable]
31+
@as = opts[:as]
32+
@link = opts[:link]
33+
@single = opts[:single]
34+
@remote = opts[:remote]
3535
apply_belongs_to_many_filter if type == :many_to_many
3636

37-
@description = opts[:description]
37+
@description = opts[:description]
3838

3939
# polymorphic has_many
40-
@polymorphic_as = opts[:polymorphic_as]
40+
@polymorphic_as = opts[:polymorphic_as]
4141
# polymorphic_belongs_to-specific
42-
@group_name = opts[:group_name]
43-
@polymorphic_child = opts[:polymorphic_child]
44-
@parent = opts[:parent]
45-
46-
@linkage_always = if opts[:linkage_always].nil?
47-
# option not provided, use default
48-
type == :belongs_to
49-
else
50-
!!opts[:linkage_always]
51-
end
42+
@group_name = opts[:group_name]
43+
@polymorphic_child = opts[:polymorphic_child]
44+
@parent = opts[:parent]
45+
@always_include_resource_ids = opts[:always_include_resource_ids]
5246

5347
if polymorphic_child?
5448
parent.resource.polymorphic << resource_class
@@ -120,8 +114,8 @@ def polymorphic_has_many?
120114
!!@polymorphic_as
121115
end
122116

123-
def linkage_always?
124-
!!@linkage_always
117+
def always_include_resource_ids?
118+
!!@always_include_resource_ids
125119
end
126120

127121
def link?

lib/graphiti/sideload/belongs_to.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
class Graphiti::Sideload::BelongsTo < Graphiti::Sideload
2+
def initialize(name, opts)
3+
opts = { always_include_resource_ids: true }.merge(opts)
4+
super(name, opts)
5+
end
6+
27
def type
38
:belongs_to
49
end

lib/graphiti/util/serializer_relationships.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ def block
4949
data_proc_ref = data_proc
5050
self_ref = self
5151
validate_link! if eagerly_validate_links?
52+
5253
proc do
5354
data { instance_eval(&data_proc_ref) }
5455

5556
# include relationship links for belongs_to relationships
5657
# https://github.com/graphiti-api/graphiti/issues/167
57-
linkage always: sideload_ref.linkage_always?
58+
linkage always: sideload_ref.always_include_resource_ids?
5859

5960
if link_ref
6061
if @proxy.query.links?
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
RSpec.describe 'relationship identifiers' do
6+
include_context 'resource testing'
7+
8+
# let(:base_scope) { { type: :positions } }
9+
let!(:employee) { PORO::Employee.create }
10+
let!(:employee2) { PORO::Employee.create }
11+
let!(:position1) do
12+
PORO::Position.create employee_id: employee.id,
13+
department_id: department1.id
14+
end
15+
let!(:position2) do
16+
PORO::Position.create employee_id: employee.id,
17+
department_id: department2.id
18+
end
19+
let!(:department1) { PORO::Department.create }
20+
let!(:department2) { PORO::Department.create }
21+
let!(:bio1) { PORO::Bio.create(employee_id: employee.id) }
22+
let!(:bio2) { PORO::Bio.create(employee_id: employee.id) }
23+
let!(:team1) do
24+
PORO::Team.create team_memberships: [
25+
PORO::TeamMembership.new(employee_id: employee.id, team_id: 1)
26+
]
27+
end
28+
let!(:team2) do
29+
PORO::Team.create team_memberships: [
30+
PORO::TeamMembership.new(employee_id: employee.id, team_id: 2)
31+
]
32+
end
33+
34+
describe 'has_many' do
35+
context 'with default' do
36+
let(:resource) do
37+
Class.new(PORO::TeamResource) do
38+
def self.name
39+
'PORO::TeamResource'
40+
end
41+
42+
has_many :employees
43+
end
44+
end
45+
46+
before do
47+
allow_any_instance_of(PORO::Team).to receive(:employees) { [employee, employee2] }
48+
render
49+
end
50+
51+
it 'does not include anything' do
52+
expect do
53+
included('employees')
54+
end.to raise_error(GraphitiSpecHelpers::Errors::NoSideloads)
55+
end
56+
57+
it 'specifies meta[:included] = false' do
58+
jsonapi_data.each do |record|
59+
expect(record.relationships['employees']['meta']['included']).to eq(false)
60+
end
61+
end
62+
63+
it 'does not includes relationship identifiers' do
64+
jsonapi_data.each do |record|
65+
data = record.relationships['employees']['data']
66+
expect(data).to be_nil
67+
end
68+
end
69+
end
70+
context 'with include directive' do
71+
let(:resource) do
72+
Class.new(PORO::TeamResource) do
73+
def self.name
74+
'PORO::TeamResource'
75+
end
76+
77+
has_many :employees do
78+
scope do |employee_ids|
79+
{
80+
type: :employees,
81+
conditions: { employee_id: employee_ids }
82+
}
83+
end
84+
end
85+
end
86+
end
87+
88+
before do
89+
params[:include] = 'employees'
90+
allow_any_instance_of(PORO::Team).to receive(:employees) { [employee, employee2] }
91+
render
92+
end
93+
94+
it 'includes employees' do
95+
expect(included('employees').map(&:id)).to eq([1, 2])
96+
end
97+
98+
it 'includes relationship identifiers' do
99+
jsonapi_data.each do |record|
100+
data = record.relationships['employees']['data']
101+
expect(data).to_not be_nil
102+
expect(data.pluck(:type).uniq).to match_array(['employees'])
103+
expect(data.pluck(:id).uniq).to match_array(%w[1 2])
104+
end
105+
end
106+
end
107+
108+
context 'without include directive and always_include_resource_ids: true' do
109+
let(:resource) do
110+
Class.new(PORO::TeamResource) do
111+
def self.name
112+
'PORO::TeamResource'
113+
end
114+
115+
has_many :employees, always_include_resource_ids: true do
116+
scope do |employee_ids|
117+
{
118+
type: :employees,
119+
conditions: { employee_id: employee_ids }
120+
}
121+
end
122+
end
123+
end
124+
end
125+
126+
before do
127+
allow_any_instance_of(PORO::Team).to receive(:employees) { [employee, employee2] }
128+
render
129+
end
130+
131+
it 'does not include anything' do
132+
expect do
133+
included('employees')
134+
end.to raise_error(GraphitiSpecHelpers::Errors::NoSideloads)
135+
end
136+
137+
it 'includes relationship identifiers' do
138+
jsonapi_data.each do |record|
139+
data = record.relationships['employees']['data']
140+
expect(data).to_not be_nil
141+
expect(data.pluck(:type).uniq).to match_array(['employees'])
142+
expect(data.pluck(:id).uniq).to match_array(%w[1 2])
143+
end
144+
end
145+
end
146+
end
147+
148+
describe 'belongs_to' do
149+
context 'with include directive' do
150+
let(:resource) do
151+
Class.new(PORO::PositionResource) do
152+
def self.name
153+
'PORO::PositionResource'
154+
end
155+
156+
belongs_to :employee
157+
end
158+
end
159+
before do
160+
params[:include] = 'employee'
161+
render
162+
end
163+
164+
it 'works' do
165+
expect(included('employees').map(&:id)).to eq([1])
166+
end
167+
168+
it 'has relationship identifiers' do
169+
jsonapi_data.each do |record|
170+
data = record.relationships['employee']['data']
171+
172+
expect(data[:type]).to eq('employees')
173+
expect(data[:id]).to eq('1')
174+
end
175+
end
176+
end
177+
178+
context 'with defaults' do
179+
let(:resource) do
180+
Class.new(PORO::PositionResource) do
181+
def self.name
182+
'PORO::PositionResource'
183+
end
184+
185+
belongs_to :employee
186+
end
187+
end
188+
189+
before do
190+
allow_any_instance_of(PORO::Position).to receive(:employee) { employee }
191+
render
192+
end
193+
194+
it 'has relationship ids' do
195+
jsonapi_data.each do |record|
196+
data = record.relationships['employee']['data']
197+
198+
expect(data[:type]).to eq('employees')
199+
expect(data[:id]).to eq('1')
200+
end
201+
end
202+
end
203+
204+
context 'with always_include_resource_ids: false' do
205+
let(:resource) do
206+
Class.new(PORO::PositionResource) do
207+
def self.name
208+
'PORO::PositionResource'
209+
end
210+
211+
belongs_to :employee, always_include_resource_ids: false do
212+
scope do |employee_ids|
213+
{
214+
type: :employees,
215+
conditions: { id: employee_ids }
216+
}
217+
end
218+
end
219+
end
220+
end
221+
222+
before do
223+
allow_any_instance_of(PORO::Position).to receive(:employee) { employee }
224+
render
225+
end
226+
227+
it 'has no relationship identifiers' do
228+
jsonapi_data.each do |record|
229+
data = record.relationships['employee']
230+
expect(data.keys).to_not include('data')
231+
end
232+
end
233+
end
234+
end
235+
end

0 commit comments

Comments
 (0)