fast_jsonapi 1.0.17 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +106 -38
  3. data/lib/extensions/has_one.rb +19 -13
  4. data/lib/fast_jsonapi.rb +2 -0
  5. data/lib/fast_jsonapi/instrumentation.rb +2 -0
  6. data/lib/fast_jsonapi/instrumentation/serializable_hash.rb +15 -0
  7. data/lib/fast_jsonapi/instrumentation/serialized_json.rb +15 -0
  8. data/lib/fast_jsonapi/instrumentation/skylight.rb +2 -0
  9. data/lib/fast_jsonapi/instrumentation/skylight/normalizers/serializable_hash.rb +22 -0
  10. data/lib/fast_jsonapi/instrumentation/skylight/normalizers/serialized_json.rb +22 -0
  11. data/lib/fast_jsonapi/multi_to_json.rb +92 -0
  12. data/lib/fast_jsonapi/object_serializer.rb +120 -91
  13. data/lib/fast_jsonapi/serialization_core.rb +44 -32
  14. data/lib/generators/serializer/USAGE +8 -0
  15. data/lib/generators/serializer/serializer_generator.rb +19 -0
  16. data/lib/generators/serializer/templates/serializer.rb.tt +6 -0
  17. metadata +48 -88
  18. data/.document +0 -5
  19. data/.rspec +0 -1
  20. data/Gemfile +0 -4
  21. data/Gemfile.lock +0 -158
  22. data/README.rdoc +0 -231
  23. data/Rakefile +0 -55
  24. data/VERSION +0 -1
  25. data/docs/collection_serializer_output.json +0 -35
  26. data/docs/object_serializer.json +0 -30
  27. data/fast_jsonapi.gemspec +0 -108
  28. data/spec/lib/extensions/active_record_spec.rb +0 -67
  29. data/spec/lib/object_serializer_caching_spec.rb +0 -68
  30. data/spec/lib/object_serializer_class_methods_spec.rb +0 -69
  31. data/spec/lib/object_serializer_hyphen_spec.rb +0 -40
  32. data/spec/lib/object_serializer_performance_spec.rb +0 -87
  33. data/spec/lib/object_serializer_spec.rb +0 -126
  34. data/spec/lib/object_serializer_struct_spec.rb +0 -31
  35. data/spec/lib/serialization_core_spec.rb +0 -84
  36. data/spec/shared/contexts/ams_context.rb +0 -83
  37. data/spec/shared/contexts/movie_context.rb +0 -192
  38. data/spec/spec_helper.rb +0 -15
@@ -1,67 +0,0 @@
1
- require 'spec_helper'
2
- require 'active_record'
3
- require 'sqlite3'
4
-
5
- describe 'active record' do
6
-
7
- # Setup DB
8
- before(:all) do
9
- @db_file = "test.db"
10
-
11
- # Open a database
12
- db = SQLite3::Database.new @db_file
13
-
14
- # Create tables
15
- db.execute_batch <<-SQL
16
- create table suppliers (
17
- name varchar(30),
18
- id int primary key
19
- );
20
-
21
- create table accounts (
22
- name varchar(30),
23
- id int primary key,
24
- supplier_id int,
25
- FOREIGN KEY (supplier_id) REFERENCES suppliers(id)
26
- );
27
- SQL
28
-
29
- # Insert records
30
- @account_id = 2
31
- @supplier_id = 1
32
- db.execute_batch <<-SQL
33
- insert into suppliers values ('Supplier1', #{@supplier_id});
34
- insert into accounts values ('Dollar Account', #{@account_id}, #{@supplier_id});
35
- SQL
36
- end
37
-
38
- # Setup Active Record
39
- before(:all) do
40
- class Supplier < ActiveRecord::Base
41
- has_one :account
42
- end
43
-
44
- class Account < ActiveRecord::Base
45
- belongs_to :supplier
46
- end
47
-
48
- ActiveRecord::Base.establish_connection(
49
- :adapter => 'sqlite3',
50
- :database => @db_file
51
- )
52
- end
53
-
54
- context 'has one patch' do
55
-
56
- it 'has account_id method for a supplier' do
57
- expect(Supplier.first.respond_to?(:account_id)).to be true
58
- expect(Supplier.first.account_id).to eq @account_id
59
- end
60
-
61
- end
62
-
63
- # Clean up DB
64
- after(:all) do
65
- File.delete(@db_file) if File.exist?(@db_file)
66
- end
67
- end
@@ -1,68 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
-
6
- context 'when caching has_many' do
7
- before(:each) do
8
- rails = OpenStruct.new
9
- rails.cache = ActiveSupport::Cache::MemoryStore.new
10
- stub_const('Rails', rails)
11
- end
12
-
13
- it 'returns correct hash when serializable_hash is called' do
14
- options = {}
15
- options[:meta] = { total: 2 }
16
- options[:include] = [:actors]
17
- serializable_hash = CachingMovieSerializer.new([movie, movie], options).serializable_hash
18
-
19
- expect(serializable_hash[:data].length).to eq 2
20
- expect(serializable_hash[:data][0][:relationships].length).to eq 3
21
- expect(serializable_hash[:data][0][:attributes].length).to eq 2
22
-
23
- expect(serializable_hash[:meta]).to be_instance_of(Hash)
24
-
25
- expect(serializable_hash[:included]).to be_instance_of(Array)
26
- expect(serializable_hash[:included][0]).to be_instance_of(Hash)
27
- expect(serializable_hash[:included].length).to eq 3
28
-
29
- serializable_hash = CachingMovieSerializer.new(movie).serializable_hash
30
-
31
- expect(serializable_hash[:data]).to be_instance_of(Hash)
32
- expect(serializable_hash[:meta]).to be nil
33
- expect(serializable_hash[:included]).to be nil
34
- end
35
-
36
- it 'uses cached values for the record' do
37
- previous_name = movie.name
38
- previous_actors = movie.actors
39
- CachingMovieSerializer.new(movie).serializable_hash
40
-
41
- movie.name = 'should not match'
42
- allow(movie).to receive(:actor_ids).and_return([99])
43
-
44
- expect(previous_name).not_to eq(movie.name)
45
- expect(previous_actors).not_to eq(movie.actors)
46
- serializable_hash = CachingMovieSerializer.new(movie).serializable_hash
47
-
48
- expect(serializable_hash[:data][:attributes][:name]).to eq(previous_name)
49
- expect(serializable_hash[:data][:relationships][:actors][:data].length).to eq movie.actors.length
50
- end
51
-
52
- it 'uses cached values for has many as specified' do
53
- previous_name = movie.name
54
- previous_actors = movie.actors
55
- CachingMovieWithHasManySerializer.new(movie).serializable_hash
56
-
57
- movie.name = 'should not match'
58
- allow(movie).to receive(:actor_ids).and_return([99])
59
-
60
- expect(previous_name).not_to eq(movie.name)
61
- expect(previous_actors).not_to eq(movie.actors)
62
- serializable_hash = CachingMovieWithHasManySerializer.new(movie).serializable_hash
63
-
64
- expect(serializable_hash[:data][:attributes][:name]).to eq(previous_name)
65
- expect(serializable_hash[:data][:relationships][:actors][:data].length).to eq previous_actors.length
66
- end
67
- end
68
- end
@@ -1,69 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
-
5
- include_context 'movie class'
6
-
7
- context 'when testing class methods of object serializer' do
8
-
9
- before(:example) do
10
- MovieSerializer.relationships_to_serialize = {}
11
- end
12
-
13
- it 'returns correct relationship hash for a has_many relationship' do
14
- MovieSerializer.has_many :roles
15
- relationship = MovieSerializer.relationships_to_serialize[:roles]
16
- expect(relationship).to be_instance_of(Hash)
17
- expect(relationship.keys).to all(be_instance_of(Symbol))
18
- expect(relationship[:id_method_name]).to end_with '_ids'
19
- expect(relationship[:record_type]).to eq 'roles'.singularize.to_sym
20
- end
21
-
22
- it 'returns correct relationship hash for a has_many relationship with overrides' do
23
- MovieSerializer.has_many :roles, id_method_name: :roles_only_ids, record_type: :super_role
24
- relationship = MovieSerializer.relationships_to_serialize[:roles]
25
- expect(relationship[:id_method_name]).to be :roles_only_ids
26
- expect(relationship[:record_type]).to be :super_role
27
- end
28
-
29
- it 'returns correct relationship hash for a belongs_to relationship' do
30
- MovieSerializer.belongs_to :area
31
- relationship = MovieSerializer.relationships_to_serialize[:area]
32
- expect(relationship).to be_instance_of(Hash)
33
- expect(relationship.keys).to all(be_instance_of(Symbol))
34
- expect(relationship[:id_method_name]).to end_with '_id'
35
- expect(relationship[:record_type]).to eq 'area'.singularize.to_sym
36
- end
37
-
38
- it 'returns correct relationship hash for a belongs_to relationship with overrides' do
39
- MovieSerializer.has_many :area, id_method_name: :blah_id, record_type: :awesome_area, serializer: :my_area
40
- relationship = MovieSerializer.relationships_to_serialize[:area]
41
- expect(relationship[:id_method_name]).to be :blah_id
42
- expect(relationship[:record_type]).to be :awesome_area
43
- expect(relationship[:serializer]).to be :MyAreaSerializer
44
- end
45
-
46
- it 'returns correct relationship hash for a has_one relationship' do
47
- MovieSerializer.has_one :area
48
- relationship = MovieSerializer.relationships_to_serialize[:area]
49
- expect(relationship).to be_instance_of(Hash)
50
- expect(relationship.keys).to all(be_instance_of(Symbol))
51
- expect(relationship[:id_method_name]).to end_with '_id'
52
- expect(relationship[:record_type]).to eq 'area'.singularize.to_sym
53
- end
54
-
55
- it 'returns correct relationship hash for a has_one relationship with overrides' do
56
- MovieSerializer.has_one :area, id_method_name: :blah_id, record_type: :awesome_area
57
- relationship = MovieSerializer.relationships_to_serialize[:area]
58
- expect(relationship[:id_method_name]).to be :blah_id
59
- expect(relationship[:record_type]).to be :awesome_area
60
- end
61
-
62
- it 'returns serializer name correctly with namespaces' do
63
- AppName::V1::MovieSerializer.has_many :area, id_method_name: :blah_id
64
- relationship = AppName::V1::MovieSerializer.relationships_to_serialize[:area]
65
- expect(relationship[:serializer]).to be :'AppName::V1::AreaSerializer'
66
- end
67
- end
68
-
69
- end
@@ -1,40 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
- include_context 'ams movie class'
6
-
7
- context 'when using hyphens for word separation in the JSON API members' do
8
- it 'returns correct hash when serializable_hash is called' do
9
- serializable_hash = HyphenMovieSerializer.new([movie, movie]).serializable_hash
10
- expect(serializable_hash[:data].length).to eq 2
11
- expect(serializable_hash[:data][0][:relationships].length).to eq 3
12
- expect(serializable_hash[:data][0][:relationships]).to have_key('movie-type'.to_sym)
13
- expect(serializable_hash[:data][0][:attributes].length).to eq 2
14
- expect(serializable_hash[:data][0][:attributes]).to have_key("release-year".to_sym)
15
-
16
- serializable_hash = HyphenMovieSerializer.new(movie_struct).serializable_hash
17
- expect(serializable_hash[:data][:relationships].length).to eq 3
18
- expect(serializable_hash[:data][:relationships]).to have_key('movie-type'.to_sym)
19
- expect(serializable_hash[:data][:attributes].length).to eq 2
20
- expect(serializable_hash[:data][:attributes]).to have_key('release-year'.to_sym)
21
- expect(serializable_hash[:data][:id]).to eq movie_struct.id.to_s
22
- end
23
-
24
- it 'returns same thing as ams' do
25
- ams_movie = build_ams_movies(1).first
26
- movie = build_movies(1).first
27
- our_json = HyphenMovieSerializer.new([movie]).serialized_json
28
- ams_json = ActiveModelSerializers::SerializableResource.new([ams_movie], key_transform: :dash).to_json
29
- expect(our_json.length).to eq (ams_json.length)
30
- end
31
-
32
- it 'returns type hypenated when trying to serializing a class with multiple words' do
33
- movie_type = MovieType.new
34
- movie_type.id = 3
35
- movie_type.name = "x"
36
- serializable_hash = HyphenMovieTypeSerializer.new(movie_type).serializable_hash
37
- expect(serializable_hash[:data][:type].to_sym).to eq 'movie-type'.to_sym
38
- end
39
- end
40
- end
@@ -1,87 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
- include_context 'ams movie class'
6
-
7
- context 'when testing performance of serialization' do
8
- it 'should create a hash of 1000 records in less than 25 ms' do
9
- movies = 1000.times.map { |_i| movie }
10
- expect { MovieSerializer.new(movies).serializable_hash }.to perform_under(25).ms
11
- end
12
-
13
- it 'should serialize 1000 records to jsonapi in less than 30 ms' do
14
- movies = 1000.times.map { |_i| movie }
15
- expect { MovieSerializer.new(movies).serialized_json }.to perform_under(30).ms
16
- end
17
-
18
- it 'should create a hash of 1000 records with includes and meta in less than 75 ms' do
19
- count = 1000
20
- movies = count.times.map { |_i| movie }
21
- options = {}
22
- options[:meta] = { total: count }
23
- options[:include] = [:actors]
24
- expect { MovieSerializer.new(movies, options).serializable_hash }.to perform_under(75).ms
25
- end
26
-
27
- it 'should serialize 1000 records to jsonapi with includes and meta in less than 75 ms' do
28
- count = 1000
29
- movies = count.times.map { |_i| movie }
30
- options = {}
31
- options[:meta] = { total: count }
32
- options[:include] = [:actors]
33
- expect { MovieSerializer.new(movies, options).serialized_json }.to perform_under(75).ms
34
- end
35
- end
36
-
37
- def print_stats(count, ams_time, our_time)
38
- format = '%-15s %-10s %s'
39
- puts ''
40
- puts format(format, 'Serializer', 'Records', 'Time')
41
- puts format(format, 'AMS serializer', count, ams_time.round(2).to_s + ' ms')
42
- puts format(format, 'Fast serializer', count, our_time.round(2).to_s + ' ms')
43
- end
44
-
45
- context 'when comparing with AMS 0.10.x' do
46
- [1, 25, 250, 1000].each do |movie_count|
47
- speed_factor = 25
48
- it "should serialize #{movie_count} records atleast #{speed_factor} times faster than AMS" do
49
- ams_movies = build_ams_movies(movie_count)
50
- movies = build_movies(movie_count)
51
- our_json = nil
52
- ams_json = nil
53
- our_serializer = MovieSerializer.new(movies)
54
- ams_serializer = ActiveModelSerializers::SerializableResource.new(ams_movies)
55
- our_time = Benchmark.measure { our_json = our_serializer.serialized_json }.real * 1000
56
- ams_time = Benchmark.measure { ams_json = ams_serializer.to_json }.real * 1000
57
- print_stats(movie_count, ams_time, our_time)
58
- expect(our_json.length).to eq ams_json.length
59
- expect { our_serializer.serialized_json }.to perform_faster_than { ams_serializer.to_json }.at_least(speed_factor).times
60
- end
61
- end
62
- end
63
-
64
- context 'when comparing with AMS 0.10.x and with includes and meta' do
65
- [1, 25, 250, 1000].each do |movie_count|
66
- speed_factor = 25
67
- it "should serialize #{movie_count} records atleast #{speed_factor} times faster than AMS" do
68
- ams_movies = build_ams_movies(movie_count)
69
- movies = build_movies(movie_count)
70
- our_json = nil
71
- ams_json = nil
72
-
73
- options = {}
74
- options[:meta] = { total: movie_count }
75
- options[:include] = [:actors, :movie_type]
76
-
77
- our_serializer = MovieSerializer.new(movies, options)
78
- ams_serializer = ActiveModelSerializers::SerializableResource.new(ams_movies, include: options[:include], meta: options[:meta])
79
- our_time = Benchmark.measure { our_json = our_serializer.serialized_json }.real * 1000
80
- ams_time = Benchmark.measure { ams_json = ams_serializer.to_json }.real * 1000
81
- print_stats(movie_count, ams_time, our_time)
82
- expect(our_json.length).to eq ams_json.length
83
- expect { our_serializer.serialized_json }.to perform_faster_than { ams_serializer.to_json }.at_least(speed_factor).times
84
- end
85
- end
86
- end
87
- end
@@ -1,126 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe FastJsonapi::ObjectSerializer do
4
- include_context 'movie class'
5
-
6
- context 'when testing instance methods of object serializer' do
7
- it 'returns correct hash when serializable_hash is called' do
8
- options = {}
9
- options[:meta] = { total: 2 }
10
- options[:include] = [:actors]
11
- serializable_hash = MovieSerializer.new([movie, movie], options).serializable_hash
12
-
13
- expect(serializable_hash[:data].length).to eq 2
14
- expect(serializable_hash[:data][0][:relationships].length).to eq 3
15
- expect(serializable_hash[:data][0][:attributes].length).to eq 2
16
-
17
- expect(serializable_hash[:meta]).to be_instance_of(Hash)
18
-
19
- expect(serializable_hash[:included]).to be_instance_of(Array)
20
- expect(serializable_hash[:included][0]).to be_instance_of(Hash)
21
- expect(serializable_hash[:included].length).to eq 3
22
-
23
- serializable_hash = MovieSerializer.new(movie).serializable_hash
24
-
25
- expect(serializable_hash[:data]).to be_instance_of(Hash)
26
- expect(serializable_hash[:meta]).to be nil
27
- expect(serializable_hash[:included]).to be nil
28
- end
29
-
30
- it 'returns correct number of records when serialized_json is called for an array' do
31
- options = {}
32
- options[:meta] = { total: 2 }
33
- json = MovieSerializer.new([movie, movie], options).serialized_json
34
- serializable_hash = JSON.parse(json)
35
- expect(serializable_hash['data'].length).to eq 2
36
- expect(serializable_hash['meta']).to be_instance_of(Hash)
37
- end
38
-
39
- it 'returns correct id when serialized_json is called for a single object' do
40
- json = MovieSerializer.new(movie).serialized_json
41
- serializable_hash = JSON.parse(json)
42
- expect(serializable_hash['data']['id']).to eq movie.id.to_s
43
- end
44
-
45
- it 'returns correct json when serializing nil' do
46
- json = MovieSerializer.new(nil).serialized_json
47
- serializable_hash = JSON.parse(json)
48
- expect(serializable_hash['data']).to eq nil
49
- end
50
-
51
- it 'returns correct json when record id is nil' do
52
- movie.id = nil
53
- json = MovieSerializer.new(movie).serialized_json
54
- serializable_hash = JSON.parse(json)
55
- expect(serializable_hash['data']['id']).to be nil
56
- end
57
-
58
- it 'returns correct json when has_many returns []' do
59
- movie.actor_ids = []
60
- json = MovieSerializer.new(movie).serialized_json
61
- serializable_hash = JSON.parse(json)
62
- expect(serializable_hash['data']['relationships']['actors']['data'].length).to eq 0
63
- end
64
-
65
- it 'returns correct json when belongs_to returns nil' do
66
- movie.owner_id = nil
67
- json = MovieSerializer.new(movie).serialized_json
68
- serializable_hash = JSON.parse(json)
69
- expect(serializable_hash['data']['relationships']['owner']['data']).to be nil
70
- end
71
-
72
- it 'returns correct json when serializing []' do
73
- json = MovieSerializer.new([]).serialized_json
74
- serializable_hash = JSON.parse(json)
75
- expect(serializable_hash['data']).to eq []
76
- end
77
-
78
- it 'returns errors when serializing with non-existent includes key' do
79
- options = {}
80
- options[:meta] = { total: 2 }
81
- options[:include] = [:blah_blah]
82
- expect { MovieSerializer.new([movie, movie], options).serializable_hash }.to raise_error(ArgumentError)
83
- end
84
-
85
- it 'returns keys when serializing with empty string/nil array includes key' do
86
- options = {}
87
- options[:meta] = { total: 2 }
88
- options[:include] = ['']
89
- expect(MovieSerializer.new([movie, movie], options).serializable_hash.keys).to eq [:data, :meta]
90
- options[:include] = [nil]
91
- expect(MovieSerializer.new([movie, movie], options).serializable_hash.keys).to eq [:data, :meta]
92
- end
93
- end
94
-
95
- context 'when testing included do block of object serializer' do
96
- it 'should set default_type based on serializer class name' do
97
- class BlahSerializer
98
- include FastJsonapi::ObjectSerializer
99
- end
100
- expect(BlahSerializer.record_type).to be :blah
101
- end
102
-
103
- it 'should set default_type for a multi word class name' do
104
- class BlahBlahSerializer
105
- include FastJsonapi::ObjectSerializer
106
- end
107
- expect(BlahBlahSerializer.record_type).to be :blah_blah
108
- end
109
-
110
- it 'shouldnt set default_type for a serializer that doesnt follow convention' do
111
- class BlahBlahSerializerBuilder
112
- include FastJsonapi::ObjectSerializer
113
- end
114
- expect(BlahBlahSerializerBuilder.record_type).to be_nil
115
- end
116
-
117
- it 'shouldnt set default_type for a serializer that doesnt follow convention' do
118
- module V1
119
- class BlahSerializer
120
- include FastJsonapi::ObjectSerializer
121
- end
122
- end
123
- expect(V1::BlahSerializer.record_type).to be :blah
124
- end
125
- end
126
- end