-
Notifications
You must be signed in to change notification settings - Fork 420
Support for polymorphic associations #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
74bb873
631754c
823d0df
4312d02
bb7bc45
2e8afd4
0c70d7c
ae00e70
e5f309c
c0cab21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,11 @@ | |
describe FastJsonapi::ObjectSerializer, performance: true do | ||
include_context 'movie class' | ||
include_context 'ams movie class' | ||
include_context 'group class' | ||
include_context 'ams group class' | ||
|
||
before(:all) { GC.disable } | ||
after(:all) { GC.enable } | ||
|
||
context 'when testing performance of serialization' do | ||
it 'should create a hash of 1000 records in less than 50 ms' do | ||
|
@@ -34,29 +39,48 @@ | |
end | ||
end | ||
|
||
def print_stats(count, ams_time, our_time) | ||
def print_stats(message, count, ams_time, our_time) | ||
format = '%-15s %-10s %s' | ||
puts '' | ||
puts message | ||
puts format(format, 'Serializer', 'Records', 'Time') | ||
puts format(format, 'AMS serializer', count, ams_time.round(2).to_s + ' ms') | ||
puts format(format, 'Fast serializer', count, our_time.round(2).to_s + ' ms') | ||
end | ||
|
||
def run_hash_benchmark(message, movie_count, our_serializer, ams_serializer) | ||
our_time = Benchmark.measure { our_hash = our_serializer.serializable_hash }.real * 1000 | ||
ams_time = Benchmark.measure { ams_hash = ams_serializer.as_json }.real * 1000 | ||
print_stats(message, movie_count, ams_time, our_time) | ||
end | ||
|
||
def run_json_benchmark(message, movie_count, our_serializer, ams_serializer) | ||
our_json = nil | ||
ams_json = nil | ||
our_time = Benchmark.measure { our_json = our_serializer.serialized_json }.real * 1000 | ||
ams_time = Benchmark.measure { ams_json = ams_serializer.to_json }.real * 1000 | ||
print_stats(message, movie_count, ams_time, our_time) | ||
return our_json, ams_json | ||
end | ||
|
||
context 'when comparing with AMS 0.10.x' do | ||
[1, 25, 250, 1000].each do |movie_count| | ||
speed_factor = 25 | ||
it "should serialize #{movie_count} records atleast #{speed_factor} times faster than AMS" do | ||
ams_movies = build_ams_movies(movie_count) | ||
movies = build_movies(movie_count) | ||
our_json = nil | ||
ams_json = nil | ||
our_serializer = MovieSerializer.new(movies) | ||
ams_serializer = ActiveModelSerializers::SerializableResource.new(ams_movies) | ||
our_time = Benchmark.measure { our_json = our_serializer.serialized_json }.real * 1000 | ||
ams_time = Benchmark.measure { ams_json = ams_serializer.to_json }.real * 1000 | ||
print_stats(movie_count, ams_time, our_time) | ||
|
||
message = "Serialize to JSON string #{movie_count} records" | ||
our_json, ams_json = run_json_benchmark(message, movie_count, our_serializer, ams_serializer) | ||
|
||
message = "Serialize to Ruby Hash #{movie_count} records" | ||
run_hash_benchmark(message, movie_count, our_serializer, ams_serializer) | ||
|
||
expect(our_json.length).to eq ams_json.length | ||
expect { our_serializer.serialized_json }.to perform_faster_than { ams_serializer.to_json }.at_least(speed_factor).times | ||
expect { our_serializer.serializable_hash }.to perform_faster_than { ams_serializer.as_json }.at_least(speed_factor).times | ||
end | ||
end | ||
end | ||
|
@@ -67,20 +91,44 @@ def print_stats(count, ams_time, our_time) | |
it "should serialize #{movie_count} records atleast #{speed_factor} times faster than AMS" do | ||
ams_movies = build_ams_movies(movie_count) | ||
movies = build_movies(movie_count) | ||
our_json = nil | ||
ams_json = nil | ||
|
||
options = {} | ||
options[:meta] = { total: movie_count } | ||
options[:include] = [:actors, :movie_type] | ||
|
||
our_serializer = MovieSerializer.new(movies, options) | ||
ams_serializer = ActiveModelSerializers::SerializableResource.new(ams_movies, include: options[:include], meta: options[:meta]) | ||
our_time = Benchmark.measure { our_json = our_serializer.serialized_json }.real * 1000 | ||
ams_time = Benchmark.measure { ams_json = ams_serializer.to_json }.real * 1000 | ||
print_stats(movie_count, ams_time, our_time) | ||
|
||
message = "Serialize to JSON string #{movie_count} with includes and meta" | ||
our_json, ams_json = run_json_benchmark(message, movie_count, our_serializer, ams_serializer) | ||
|
||
message = "Serialize to Ruby Hash #{movie_count} with includes and meta" | ||
run_hash_benchmark(message, movie_count, our_serializer, ams_serializer) | ||
|
||
expect(our_json.length).to eq ams_json.length | ||
expect { our_serializer.serialized_json }.to perform_faster_than { ams_serializer.to_json }.at_least(speed_factor).times | ||
expect { our_serializer.serializable_hash }.to perform_faster_than { ams_serializer.as_json }.at_least(speed_factor).times | ||
end | ||
end | ||
end | ||
|
||
context 'when comparing with AMS 0.10.x and with polymorphic has_many' do | ||
[1, 25, 250, 1000].each do |group_count| | ||
speed_factor = 25 | ||
it "should serialize #{group_count} records at least #{speed_factor} times faster than AMS" do | ||
ams_groups = build_ams_groups(group_count) | ||
groups = build_groups(group_count) | ||
options = {} | ||
our_serializer = GroupSerializer.new(groups, options) | ||
ams_serializer = ActiveModelSerializers::SerializableResource.new(ams_groups) | ||
|
||
message = "Serialize to JSON string #{group_count} with polymorphic has_many" | ||
our_json, ams_json = run_json_benchmark(message, group_count, our_serializer, ams_serializer) | ||
|
||
message = "Serialize to Ruby Hash #{group_count} with polymorphic has_many" | ||
run_hash_benchmark(message, group_count, our_serializer, ams_serializer) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add the jsonapi_serializer to the benchmark. Refer to line 80 in https://github.com/Netflix/fast_jsonapi/blob/dev/spec/lib/object_serializer_performance_spec.rb There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it |
||
|
||
expect(our_json.length).to eq ams_json.length | ||
expect { our_serializer.serialized_json }.to perform_faster_than { ams_serializer.to_json }.at_least(speed_factor).times | ||
expect { our_serializer.serializable_hash }.to perform_faster_than { ams_serializer.as_json }.at_least(speed_factor).times | ||
end | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
RSpec.shared_context 'ams group class' do | ||
before(:context) do | ||
# models | ||
class AMSPerson < ActiveModelSerializers::Model | ||
attr_accessor :id, :first_name, :last_name | ||
end | ||
|
||
class AMSGroup < ActiveModelSerializers::Model | ||
attr_accessor :id, :name, :groupees | ||
end | ||
|
||
# serializers | ||
class AMSPersonSerializer < ActiveModel::Serializer | ||
type 'person' | ||
attributes :first_name, :last_name | ||
end | ||
|
||
class AMSGroupSerializer < ActiveModel::Serializer | ||
type 'group' | ||
attributes :name | ||
has_many :groupees | ||
end | ||
end | ||
|
||
after(:context) do | ||
classes_to_remove = %i[AMSPerson AMSGroup AMSPersonSerializer AMSGroupSerializer] | ||
classes_to_remove.each do |klass_name| | ||
Object.send(:remove_const, klass_name) if Object.constants.include?(klass_name) | ||
end | ||
end | ||
|
||
let(:ams_groups) do | ||
group_count = 0 | ||
person_count = 0 | ||
3.times.map do |i| | ||
group = AMSGroup.new | ||
group.id = group_count + 1 | ||
group.name = "Test Group #{group.id}" | ||
group_count = group.id | ||
|
||
person = AMSPerson.new | ||
person.id = person_count + 1 | ||
person.last_name = "Last Name #{person.id}" | ||
person.first_name = "First Name #{person.id}" | ||
person_count = person.id | ||
|
||
child_group = AMSGroup.new | ||
child_group.id = group_count + 1 | ||
child_group.name = "Test Group #{child_group.id}" | ||
group_count = child_group.id | ||
|
||
group.groupees = [person, child_group] | ||
group | ||
end | ||
end | ||
|
||
let(:ams_person) do | ||
ams_person = AMSPerson.new | ||
ams_person.id = 3 | ||
ams_person | ||
end | ||
|
||
def build_ams_groups(count) | ||
group_count = 0 | ||
person_count = 0 | ||
count.times.map do |i| | ||
group = AMSGroup.new | ||
group.id = group_count + 1 | ||
group.name = "Test Group #{group.id}" | ||
group_count = group.id | ||
|
||
person = AMSPerson.new | ||
person.id = person_count + 1 | ||
person.last_name = "Last Name #{person.id}" | ||
person.first_name = "First Name #{person.id}" | ||
person_count = person.id | ||
|
||
child_group = AMSGroup.new | ||
child_group.id = group_count + 1 | ||
child_group.name = "Test Group #{child_group.id}" | ||
group_count = child_group.id | ||
|
||
group.groupees = [person, child_group] | ||
group | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@christophersansone Not yet a method like you suggested (that's something I can refactor, tho), but caching like a boss...