http_api_tools 0.3.0
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 +15 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +479 -0
- data/Rakefile +4 -0
- data/http_api_tools.gemspec +29 -0
- data/lib/http_api_tools/base_json_serializer.rb +103 -0
- data/lib/http_api_tools/expanded_relation_includes.rb +77 -0
- data/lib/http_api_tools/identity_map.rb +42 -0
- data/lib/http_api_tools/json_serializer_dsl.rb +62 -0
- data/lib/http_api_tools/model/acts_like_active_model.rb +16 -0
- data/lib/http_api_tools/model/attributes.rb +159 -0
- data/lib/http_api_tools/model/has_many_array.rb +47 -0
- data/lib/http_api_tools/model/transformers/date_time_transformer.rb +31 -0
- data/lib/http_api_tools/model/transformers/registry.rb +55 -0
- data/lib/http_api_tools/model.rb +2 -0
- data/lib/http_api_tools/nesting/json_serializer.rb +45 -0
- data/lib/http_api_tools/nesting/relation_loader.rb +89 -0
- data/lib/http_api_tools/relation_includes.rb +146 -0
- data/lib/http_api_tools/serializer_registry.rb +27 -0
- data/lib/http_api_tools/sideloading/json_deserializer.rb +121 -0
- data/lib/http_api_tools/sideloading/json_deserializer_mapping.rb +27 -0
- data/lib/http_api_tools/sideloading/json_serializer.rb +125 -0
- data/lib/http_api_tools/sideloading/relation_sideloader.rb +79 -0
- data/lib/http_api_tools/sideloading/sideload_map.rb +54 -0
- data/lib/http_api_tools/type_key_resolver.rb +27 -0
- data/lib/http_api_tools/version.rb +3 -0
- data/lib/http_api_tools.rb +10 -0
- data/reports/empty.png +0 -0
- data/reports/minus.png +0 -0
- data/reports/plus.png +0 -0
- data/spec/http_api_tools/expanded_relation_includes_spec.rb +31 -0
- data/spec/http_api_tools/identity_map_spec.rb +31 -0
- data/spec/http_api_tools/model/attributes_spec.rb +170 -0
- data/spec/http_api_tools/model/has_many_array_spec.rb +48 -0
- data/spec/http_api_tools/model/transformers/date_time_transformer_spec.rb +36 -0
- data/spec/http_api_tools/model/transformers/registry_spec.rb +53 -0
- data/spec/http_api_tools/nesting/json_serializer_spec.rb +173 -0
- data/spec/http_api_tools/relation_includes_spec.rb +196 -0
- data/spec/http_api_tools/sideloading/json_deserializer_spec.rb +93 -0
- data/spec/http_api_tools/sideloading/json_serializer_performance_spec.rb +51 -0
- data/spec/http_api_tools/sideloading/json_serializer_spec.rb +174 -0
- data/spec/http_api_tools/sideloading/sideload_map_spec.rb +59 -0
- data/spec/http_api_tools/support/company_deserializer_mapping.rb +11 -0
- data/spec/http_api_tools/support/person_deserializer_mapping.rb +9 -0
- data/spec/http_api_tools/support/spec_models.rb +89 -0
- data/spec/http_api_tools/support/spec_nesting_serializers.rb +41 -0
- data/spec/http_api_tools/support/spec_sideloading_serializers.rb +41 -0
- data/spec/http_api_tools/type_key_resolver_spec.rb +19 -0
- data/spec/spec_helper.rb +8 -0
- metadata +214 -0
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'http_api_tools/relation_includes'
|
3
|
+
|
4
|
+
module HttpApiTools
|
5
|
+
describe RelationIncludes do
|
6
|
+
|
7
|
+
context 'when constructed with no value' do
|
8
|
+
let(:includes) { RelationIncludes.new }
|
9
|
+
|
10
|
+
it 'is empty, not present and blank' do
|
11
|
+
expect(includes).to be_empty
|
12
|
+
expect(includes).to be_blank
|
13
|
+
expect(includes).to_not be_present
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'equality' do
|
18
|
+
|
19
|
+
it 'works as expected' do
|
20
|
+
one = [ :tags, { images: [:comments] }, { reviews: [:author] } ]
|
21
|
+
two = [ :tags, { images: [:comments] }, { reviews: [:author] } ]
|
22
|
+
expect(RelationIncludes.new(*one)).to eq RelationIncludes.new(*two)
|
23
|
+
|
24
|
+
one = [ { reviews: [:author] }, :tags, { images: [:comments] } ]
|
25
|
+
two = [ :tags, { images: [:comments] }, { reviews: [:author] } ]
|
26
|
+
expect(RelationIncludes.new(*one)).to eq RelationIncludes.new(*two)
|
27
|
+
|
28
|
+
one = [ :tags, { images: [:comments] }, { reviews: [:author] } ]
|
29
|
+
two = [ :tags, { images: [:comments] }, :reviews ]
|
30
|
+
expect(RelationIncludes.new(*one)).to_not eq RelationIncludes.new(*two)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.from_string' do
|
35
|
+
|
36
|
+
let(:string) { 'a,a.b,a.b.c,b,c' }
|
37
|
+
let(:includes) { RelationIncludes.from_string(string) }
|
38
|
+
|
39
|
+
it 'creates single level includes' do
|
40
|
+
expect(includes).to include :b
|
41
|
+
expect(includes).to include :c
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'creates nested includes' do
|
45
|
+
expect(includes).to include({ a: [{ b: [:c] }] })
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'creates same structure when implicit parts of the path are removed' do
|
49
|
+
simplified_params = 'a.b.c,b,c'
|
50
|
+
simplified_includes = RelationIncludes.from_string(simplified_params)
|
51
|
+
expect(includes).to eq simplified_includes
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when a nil or empty string is provided' do
|
55
|
+
|
56
|
+
it 'returns a new includes' do
|
57
|
+
expect(RelationIncludes.from_string(nil)).to eq RelationIncludes.new
|
58
|
+
expect(RelationIncludes.from_string('')).to eq RelationIncludes.new
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#to_s" do
|
64
|
+
|
65
|
+
it "converts to dot-notation specified by the JSON API spec, sorted alphabetically" do
|
66
|
+
includes = RelationIncludes.new(:reviews, { images: [{ comments: [:author] }] }, :hashtags)
|
67
|
+
expect(includes.to_s).to eq 'hashtags,images,images.comments,images.comments.author,reviews'
|
68
|
+
|
69
|
+
includes = RelationIncludes.new(:hashtags, { images: [{ comments: [:author, :rating] }] }, :reviews)
|
70
|
+
expect(includes.to_s).to eq 'hashtags,images,images.comments,images.comments.author,images.comments.rating,reviews'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#&' do
|
75
|
+
|
76
|
+
let(:relations) { [ :tags, { images: [:comments] }, { reviews: [:author] } ] }
|
77
|
+
let(:includes) { RelationIncludes.new(*relations) }
|
78
|
+
|
79
|
+
let(:scenarios) do
|
80
|
+
[
|
81
|
+
{
|
82
|
+
includes: [ { images: [:comments] } ],
|
83
|
+
other: [ { images: [:comments] } ],
|
84
|
+
expected: [ { images: [:comments] } ]
|
85
|
+
},
|
86
|
+
{
|
87
|
+
includes: [ { images: [:comments, :hashtags]} ],
|
88
|
+
other: [ { images: [:comments] } ],
|
89
|
+
expected: [ { images: [:comments] } ]
|
90
|
+
},
|
91
|
+
{
|
92
|
+
includes: [ { images: [:comments] } ],
|
93
|
+
other: [ { images: [:comments, :hashtags] } ],
|
94
|
+
expected: [ { images: [:comments] } ]
|
95
|
+
},
|
96
|
+
{
|
97
|
+
includes: [ :reviews, { images: [{ comments: [:author] }] }, :hashtags ],
|
98
|
+
other: [ :reviews, { images: [{ comments: [:author] }] }, :hashtags ],
|
99
|
+
expected: [ :reviews, { images: [{ comments: [:author] }] }, :hashtags ]
|
100
|
+
},
|
101
|
+
{
|
102
|
+
includes: [ :reviews, { images: [{ comments: [:author] }] } ],
|
103
|
+
other: [ :reviews, { images: [ :comments ]} ],
|
104
|
+
expected: [ :reviews, { images: [ :comments ]} ]
|
105
|
+
},
|
106
|
+
{
|
107
|
+
includes: [ :reviews, { images: [ :comments ]} ],
|
108
|
+
other: [ :reviews, { images: [{ comments: [:author] }] } ],
|
109
|
+
expected: [ :reviews, { images: [ :comments ]} ]
|
110
|
+
},
|
111
|
+
{
|
112
|
+
includes: [ :reviews, { images: [{ comments: [:author] }] } ],
|
113
|
+
other: [ :reviews, :images ],
|
114
|
+
expected: [ :reviews, :images ]
|
115
|
+
},
|
116
|
+
{
|
117
|
+
includes: [ :reviews, {images: [{ comments: [:author] }] } ],
|
118
|
+
other: [ :reviews, :images, :hashtags ],
|
119
|
+
expected: [ :reviews, :images ]
|
120
|
+
}
|
121
|
+
]
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'reuturns a new RelationIncludes as a deep intersection between two RelationIncludes' do
|
125
|
+
scenarios.each do |scenario|
|
126
|
+
includes = scenario[:includes]
|
127
|
+
other = scenario[:other]
|
128
|
+
expected = scenario[:expected]
|
129
|
+
|
130
|
+
intersection = RelationIncludes.new(*includes) & RelationIncludes.new(*other)
|
131
|
+
expect(intersection).to eq RelationIncludes.new(*expected)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "#includes_relation?" do
|
138
|
+
|
139
|
+
let(:includes) { RelationIncludes.new(:a, { b: [:c] }) }
|
140
|
+
|
141
|
+
it "includes correct relations when a symbol" do
|
142
|
+
expect(includes.includes_relation?(:a)).to be_true
|
143
|
+
end
|
144
|
+
|
145
|
+
it "includes relations when key of object" do
|
146
|
+
expect(includes.includes_relation?(:b)).to be_true
|
147
|
+
end
|
148
|
+
|
149
|
+
it "does not include unspecified relations" do
|
150
|
+
expect(includes.includes_relation?(:x)).to be_false
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#include" do
|
156
|
+
|
157
|
+
let(:includes) { RelationIncludes.new(:a, { b: [:c] }) }
|
158
|
+
|
159
|
+
it "includes new relations" do
|
160
|
+
includes.include([:y, :z])
|
161
|
+
expect(includes).to include :y
|
162
|
+
expect(includes).to include :z
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#find" do
|
167
|
+
|
168
|
+
let(:includes) { RelationIncludes.new(:a, { b: [:c] }) }
|
169
|
+
|
170
|
+
it "finds include by key" do
|
171
|
+
expect(includes.find(:b)).to eq({ b: [:c] })
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "#nested_includes_for" do
|
176
|
+
|
177
|
+
let(:includes) { RelationIncludes.new(:a, { b: [:c] }) }
|
178
|
+
|
179
|
+
it "returns nested includes" do
|
180
|
+
expect(includes.nested_includes_for(:b)).to eq([:c])
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#for_query" do
|
185
|
+
|
186
|
+
let(:includes) { RelationIncludes.new(:employer, { skills: [:person] }).for_query(HttpApiTools::Sideloading::PersonSerializer) }
|
187
|
+
|
188
|
+
it "creates includes for included relationships and has_many relationships for fetching ids" do
|
189
|
+
expect(includes.find(:employer)).to eq({ employer: [:employees] })
|
190
|
+
expect(includes.find(:skills)).to eq({ skills: [{ person: [:skills] }] })
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'http_api_tools/sideloading/json_deserializer'
|
5
|
+
require 'http_api_tools/support/company_deserializer_mapping'
|
6
|
+
require 'http_api_tools/support/person_deserializer_mapping'
|
7
|
+
|
8
|
+
module HttpApiTools
|
9
|
+
|
10
|
+
module Sideloading
|
11
|
+
|
12
|
+
describe JsonDeserializer do
|
13
|
+
|
14
|
+
let(:json) do
|
15
|
+
{
|
16
|
+
'meta' => {
|
17
|
+
'type' => 'company',
|
18
|
+
'root_key' => 'companies'
|
19
|
+
},
|
20
|
+
'companies' => [{
|
21
|
+
'id' => 1,
|
22
|
+
'name' => "Hooroo",
|
23
|
+
'brand' => "We are travellers or something",
|
24
|
+
'links' => {
|
25
|
+
'employees' => [10, 11, 12],
|
26
|
+
'address' => 20,
|
27
|
+
'suppliers' => [30],
|
28
|
+
'parent_company' => 40
|
29
|
+
}
|
30
|
+
}],
|
31
|
+
'linked' => {
|
32
|
+
'people' => [
|
33
|
+
{'id' => 10, 'first_name' => 'Rob', 'links' => { 'employer' => 1 } },
|
34
|
+
{'id' => 11, 'first_name' => 'Stu', 'links' => { 'employer' => 1 } },
|
35
|
+
{'id' => 12, 'first_name' => 'Dan', 'links' => { 'employer' => 1 } },
|
36
|
+
],
|
37
|
+
'addresses' => [
|
38
|
+
{'id' => 20, 'street_address' => "1 Burke Street"}
|
39
|
+
]
|
40
|
+
}
|
41
|
+
|
42
|
+
}
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:company) do
|
47
|
+
JsonDeserializer.new(json).deserialize.first
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "basic deserialization" do
|
51
|
+
|
52
|
+
it "creates model from the root object" do
|
53
|
+
expect(company.id).to eq json['companies'][0]['id']
|
54
|
+
expect(company.name).to eq json['companies'][0]['name']
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can set read-only attributes" do
|
58
|
+
expect(company.brand).to eq json['companies'][0]['brand']
|
59
|
+
end
|
60
|
+
|
61
|
+
it "includes sideloaded has many relationships" do
|
62
|
+
expect(company.employees.size).to eql 3
|
63
|
+
expect(company.employees.first.first_name).to eq json['linked']['people'].first['first_name']
|
64
|
+
end
|
65
|
+
|
66
|
+
it "includes sideloaded has_one relationships" do
|
67
|
+
expect(company.address.street_address).to eq json['linked']['addresses'].first['street_address']
|
68
|
+
end
|
69
|
+
|
70
|
+
it "includes circular relationships" do
|
71
|
+
expect(company.employees.first.employer.name).to eq json['companies'][0]['name']
|
72
|
+
end
|
73
|
+
|
74
|
+
it "has_many relationships without sideloaded data are set to an empty array" do
|
75
|
+
expect(company.suppliers).to eql []
|
76
|
+
end
|
77
|
+
|
78
|
+
it "has_many relationships without sideloaded data have relation_ids attribute set to the ids of the relationship" do
|
79
|
+
expect(company.supplier_ids).to eql [30]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "has_one relationships without sideloaded data are set to nil" do
|
83
|
+
expect(company.parent_company).to eql nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it "has_one relationships without sideloaded data sets the relation_id attribute set to the id" do
|
87
|
+
expect(company.parent_company_id).to eql 40
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ruby-prof'
|
3
|
+
|
4
|
+
module HttpApiTools
|
5
|
+
module Sideloading
|
6
|
+
|
7
|
+
# Rudimentary performance profiler - uncomment to run on demand for now
|
8
|
+
|
9
|
+
|
10
|
+
# describe JsonSerializer do
|
11
|
+
|
12
|
+
# let!(:companies) do
|
13
|
+
# start = Time.now
|
14
|
+
# companies = (1..100).map do |company_id|
|
15
|
+
# company = Company.new(id: company_id, name: "Company #{rand(company_id)}")
|
16
|
+
# people = (1..100).map do |person_id|
|
17
|
+
# person = Person.new(id: person_id, first_name: "First #{rand(person_id)}", last_name: "Last #{rand(person_id)}", dob: Date.today, email: 'user@example.com', employer: company)
|
18
|
+
# skills = (1..20).map do |skill_id|
|
19
|
+
# skill = Skill.new(id: skill_id, name: "Skill #{rand(skill_id)}", description: "abc123" * 500, person: person)
|
20
|
+
# end
|
21
|
+
# person.skills = skills
|
22
|
+
# person
|
23
|
+
# end
|
24
|
+
# company.employees = people
|
25
|
+
# company
|
26
|
+
# end
|
27
|
+
# puts "BUILD MODEL: #{(Time.now - start) * 1000} ms"
|
28
|
+
# companies
|
29
|
+
# end
|
30
|
+
|
31
|
+
# it "serializes" do
|
32
|
+
# RubyProf.start
|
33
|
+
# serialized = CompanySerializer.new(companies).includes(:employer, {employees: [:skills]}).as_json
|
34
|
+
# result = RubyProf.stop
|
35
|
+
# printer = RubyProf::CallStackPrinter.new(result)
|
36
|
+
# report_file = File.open(File.expand_path("../../../reports/profile_report.html", __FILE__), "w")
|
37
|
+
# printer.print(report_file)
|
38
|
+
|
39
|
+
# start = Time.now
|
40
|
+
# serialized = CompanySerializer.new(companies).includes(:employer, {employees: [:skills]}).as_json
|
41
|
+
# puts "SERIALIZE: #{(Time.now - start) * 1000} ms"
|
42
|
+
|
43
|
+
# start = Time.now
|
44
|
+
# JSON.fast_generate(serialized)
|
45
|
+
# puts "TO_JSON: #{(Time.now - start) * 1000} ms"
|
46
|
+
|
47
|
+
# end
|
48
|
+
|
49
|
+
# end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'http_api_tools/sideloading/json_serializer'
|
5
|
+
|
6
|
+
module HttpApiTools
|
7
|
+
module Sideloading
|
8
|
+
|
9
|
+
describe JsonSerializer do
|
10
|
+
|
11
|
+
let(:company) { Company.new(id: 1, name: 'Hooroo') }
|
12
|
+
let(:person) { Person.new(id: 2, first_name: 'Rob', last_name: 'Monie') }
|
13
|
+
let(:skill) { Skill.new(id: 3, name: "JSON Serialization") }
|
14
|
+
let(:skill2) { Skill.new(id: 4, name: "JSON Serialization 2") }
|
15
|
+
|
16
|
+
before do
|
17
|
+
company.employees = [person]
|
18
|
+
person.employer = company
|
19
|
+
person.skills = [skill, skill2]
|
20
|
+
skill.person = person
|
21
|
+
skill2.person = person
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "serialization of data" do
|
25
|
+
context "with a single top-level serializable object thttp_api_tools has relationship names different to model class" do
|
26
|
+
|
27
|
+
context "without any includes" do
|
28
|
+
|
29
|
+
let(:serialized) { PersonSerializer.new(person).as_json.with_indifferent_access }
|
30
|
+
let(:serialized_person) { serialized[:people].first }
|
31
|
+
|
32
|
+
it "serializes basic attributes" do
|
33
|
+
expect(serialized_person[:id]).to eql person.id
|
34
|
+
expect(serialized_person[:first_name]).to eql person.first_name
|
35
|
+
expect(serialized_person[:last_name]).to eql person.last_name
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'expect basic attributes with no value' do
|
39
|
+
expect(serialized_person.has_key?(:dob)).to be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "serializes attributes defined as methods on the serializer" do
|
43
|
+
expect(serialized_person[:full_name]).to eql "#{person.first_name} #{person.last_name}"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "serializes relationships as ids" do
|
47
|
+
expect(serialized_person[:links][:employer]).to eql person.employer.id
|
48
|
+
expect(serialized_person[:links][:skills]).to eql person.skills.map(&:id)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "doesn't serialize any relationships" do
|
52
|
+
expect(serialized[:linked][:companies]).to be_nil
|
53
|
+
expect(serialized[:linked][:skills]).to be_nil
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "with relations specified as includes" do
|
59
|
+
|
60
|
+
let(:serializer) { PersonSerializer.new(person).includes(:employer, {skills: [:person]}) }
|
61
|
+
|
62
|
+
let(:serialized) do
|
63
|
+
serializer.as_json.with_indifferent_access
|
64
|
+
end
|
65
|
+
|
66
|
+
let(:serialized_person) { serialized[:people].first }
|
67
|
+
|
68
|
+
it "serializes relationships as ids" do
|
69
|
+
expect(serialized_person[:links][:employer]).to eql person.employer.id
|
70
|
+
expect(serialized_person[:links][:skills]).to eql person.skills.map(&:id)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "sideloads has_one relationships" do
|
74
|
+
expect(serialized[:linked][:companies].first[:name]).to eql person.employer.name
|
75
|
+
end
|
76
|
+
|
77
|
+
it "sideloads has_many relationships" do
|
78
|
+
expect(serialized[:linked][:skills].first[:name]).to eql person.skills.first.name
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with an array as the serializable object" do
|
86
|
+
|
87
|
+
let(:relation) do
|
88
|
+
[person, second_person]
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:second_person) { Person.new(id: 5, first_name: 'Stu', last_name: 'Liston') }
|
92
|
+
let(:serialized) { JSON.parse(PersonSerializer.new(relation).to_json).with_indifferent_access }
|
93
|
+
|
94
|
+
before do
|
95
|
+
company.employees = [person, second_person]
|
96
|
+
person.employer = company
|
97
|
+
second_person.employer = company
|
98
|
+
person.skills = [skill]
|
99
|
+
second_person.skills = []
|
100
|
+
skill.person = person
|
101
|
+
end
|
102
|
+
|
103
|
+
it "serializes basic attributes of all items in the array" do
|
104
|
+
expect(serialized[:people][0][:id]).to eql person.id
|
105
|
+
expect(serialized[:people][0][:first_name]).to eql person.first_name
|
106
|
+
expect(serialized[:people][0][:last_name]).to eql person.last_name
|
107
|
+
expect(serialized[:people][0][:id]).to eql person.id
|
108
|
+
|
109
|
+
expect(serialized[:people][1][:id]).to eql second_person.id
|
110
|
+
expect(serialized[:people][1][:first_name]).to eql second_person.first_name
|
111
|
+
expect(serialized[:people][1][:last_name]).to eql second_person.last_name
|
112
|
+
expect(serialized[:people][1][:id]).to eql second_person.id
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "meta data" do
|
118
|
+
|
119
|
+
let(:serializer) { PersonSerializer.new(person) }
|
120
|
+
|
121
|
+
it "adds root key" do
|
122
|
+
expect(serializer.as_json[:meta][:root_key]).to eql 'people'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "adds type" do
|
126
|
+
expect(serializer.as_json[:meta][:type]).to eql 'person'
|
127
|
+
end
|
128
|
+
|
129
|
+
it "allows meta data to be added" do
|
130
|
+
serializer.meta(offset: 0, limit: 10)
|
131
|
+
expect(serializer.as_json[:meta][:offset]).to eql 0
|
132
|
+
expect(serializer.as_json[:meta][:limit]).to eql 10
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "limiting sideloadable data" do
|
138
|
+
|
139
|
+
class LimitedSideloadingPersonSerializer < PersonSerializer
|
140
|
+
includable :employer, :skills
|
141
|
+
end
|
142
|
+
|
143
|
+
let(:unlimited_serialized) { PersonSerializer.new(person).includes(:employer, {skills: [:person]}).as_json.with_indifferent_access }
|
144
|
+
|
145
|
+
let(:limited_serialized) do
|
146
|
+
LimitedSideloadingPersonSerializer.new(person).includes(:employer, {skills: [:person]}).as_json.with_indifferent_access
|
147
|
+
end
|
148
|
+
|
149
|
+
it "does not limit sideloading if not limited in serializer" do
|
150
|
+
expect(unlimited_serialized[:linked][:people].first[:id]).to eq person.id
|
151
|
+
end
|
152
|
+
|
153
|
+
it "allows sideloading of includable relations" do
|
154
|
+
expect(limited_serialized[:linked][:skills].first[:name]).to eql person.skills.first.name
|
155
|
+
end
|
156
|
+
|
157
|
+
it "prevents sideloading of non-includable relations" do
|
158
|
+
expect(limited_serialized[:linked][:people]).to be_nil
|
159
|
+
end
|
160
|
+
|
161
|
+
it "includes whttp_api_tools is includables in meta" do
|
162
|
+
expect(limited_serialized[:meta][:includable]).to eq 'employer,skills'
|
163
|
+
end
|
164
|
+
|
165
|
+
it "includes whttp_api_tools was included in meta" do
|
166
|
+
expect(limited_serialized[:meta][:included]).to eq 'employer,skills'
|
167
|
+
expect(unlimited_serialized[:meta][:included]).to eq 'employer,skills,skills.person'
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|